#include <stm32f10x_conf.h>
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "timer.h"
#include "pwm.h"
#include "gpio.h"
#include "fsmc.h"
#include "iic.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "task_com.h"
#include "task_motor.h"
#include "task_led.h"
#include "at_cmd.h"
#include "string.h"
#include "lib5500.h"
#include "flash.h"
#include "iwdg.h"
#include "ws2812_sim.h"

#define LOG_LEVEL_DISABLE -1
#define LOG_LEVEL_ERROR 0
#define LOG_LEVEL_WARNING 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3

#define LOG_LEVEL LOG_LEVEL_DEBUG

#if defined(LOG_LEVEL) && (LOG_LEVEL >= LOG_LEVEL_DEBUG)
#define LOGD(fmt, ...) printf("[D %s,%d] "fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__) //%16s,%3d
#else
#define LOGD(fmt, ...)
#endif

#if defined(LOG_LEVEL) && (LOG_LEVEL >= LOG_LEVEL_INFO)
#define LOGI(fmt, ...) printf("[I %s,%d] "fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define LOGI(fmt, ...)
#endif

#if defined(LOG_LEVEL) && (LOG_LEVEL >= LOG_LEVEL_WARNING)
#define LOGW(fmt, ...) printf( "[W %s,%d] "fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define LOGW(fmt, ...)
#endif

#if defined(LOG_LEVEL) && (LOG_LEVEL >= LOG_LEVEL_ERROR)
#define LOGE(fmt, ...) printf( "[E %s,%d] "fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define LOGE(fmt, ...)
#endif

#define MARK LOGD("\n");

SemaphoreHandle_t SensorReadLock;
SemaphoreHandle_t UdpSendLock;
SemaphoreHandle_t slave_ready_lock;


void TaskMaster( void *pvParameters );
void TaskSlave( void *pvParameters );
static void SPI1_init(void);
static void SPI2_init(void);

void Initialization()
{
MCU_INIT(RCC_PLLMul_9); //?????: 12MHz * 6 = 72MHz
Delay_Init(72);
Uart_Init(USART1,115200,72); //???????,PCLK1??????PCLK??RCC_HCLK_Div1???
Uart_Init(USART2,9600,36); //?????????,PCLK2??????PCLK??RCC_HCLK_Div1???
// Uart_Init(USART3,115200,36); //???????????
printf("\r\n\r\n****************Build:%s %s****************\r\n",__DATE__,__TIME__);
// UartSendStr(USART2,"System start\r\n");
}

int main(void)
{
Initialization();

// QStepMotorCommand = xQueueCreate( 1,sizeof(int) );
// QHostCommand = xQueueCreate( 16,sizeof(int) );

SensorReadLock = xSemaphoreCreateMutex();
xSemaphoreGive(SensorReadLock);

UdpSendLock = xSemaphoreCreateMutex();
xSemaphoreGive(UdpSendLock);

slave_ready_lock = xSemaphoreCreateMutex();
xSemaphoreTake(slave_ready_lock, 0 * portTICK_PERIOD_MS);

/* Start the tasks defined within this file/specific to this demo. */
// xTaskCreate( TaskComm, "task2", 2 * 256, NULL, 2, NULL );
xTaskCreate( TaskMaster, "task1", 4 * 256, NULL, 3, NULL );
xTaskCreate( TaskSlave, "task2", 4 * 256, NULL, 1, NULL );

/* Start the scheduler. */
vTaskStartScheduler();

while(1);

}


#define USART1_RX_DMA_BUFF_SIZE 128
#define SPI2_RX_DMA_BUFF_SIZE 32
#define SPI2_TX_DMA_BUFF_SIZE 32


static void read_uart_input_buff(void);
static void USART1_RX_DMA_Init(void);
static void SPI2_RX_DMA_Init(void);
static void SPI2_TX_DMA_Init(void);
static void read_spi2_input_buff(void);
static void SPI2_frame_handler(uint8_t data);

static u32 s_frame_buff[1024];
static u8 USART1_RX_DMA_Buff[USART1_RX_DMA_BUFF_SIZE]; //????????????��????????????????????��????????????
static u8 SPI2_RX_DMA_Buff[SPI2_RX_DMA_BUFF_SIZE];
static u8 SPI2_TX_DMA_Buff[SPI2_TX_DMA_BUFF_SIZE] = {0xA0, 0x0 , 0x1 , 0x2 , 0x3 , 0x4 , 0x5 , 0x6 , 0x7 , 0x8 , 0x9 , 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30};

void TaskMaster( void *pvParameters )
{
LOGI("TaskMaster start...\r\n");

// USART1_RX_DMA_Init();
// ws2812_sim_init();
SPI1_init();


xSemaphoreTake(slave_ready_lock, portMAX_DELAY);

uint8_t count = 0;

while(1)
{
// LOGI("test %d %d\r\n", count, DMA_GetCurrDataCounter(DMA1_Channel4));

// read_uart_input_buff();

static int state = 0;
if (state == 0) {
SPIx_ReadWriteByte(0xA5); // preamble
SPIx_ReadWriteByte(0x5A);
SPIx_ReadWriteByte(0x55);
SPIx_ReadWriteByte(0xAA);
SPIx_ReadWriteByte(count); // addr
SPIx_ReadWriteByte(~count); // cmd

count++;

state = 1;
} else if (state == 1) {
uint8_t data = SPIx_ReadWriteByte(0xFF); // dummy byte
LOGI("%.2X\r\n", data);
if (data == 0xA0) {
for (int i = 0; i < 31; i++) {
uint8_t data = SPIx_ReadWriteByte(0xFF);
printf("%.2X ", data);
}
printf("\r\n");
state = 0;
}
} else if (state == 2) {
}


vTaskDelay(10);
}
}

void TaskSlave( void *pvParameters )
{
LOGI("TaskSlave start...\r\n");

SPI2_init();
SPI2_RX_DMA_Init();
SPI2_TX_DMA_Init();

xSemaphoreGive(slave_ready_lock);

uint8_t count = 0;

while(1)
{
read_spi2_input_buff();

vTaskDelay(1);
}
}

static void USART1_RX_DMA_Init(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

DMA_DeInit(DMA1_Channel5);

DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (u32)USART1_RX_DMA_Buff;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = sizeof(USART1_RX_DMA_Buff);
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel5,&DMA_InitStruct);

DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,DISABLE);
DMA_ITConfig(DMA1_Channel5,DMA_IT_HT,DISABLE);
DMA_ITConfig(DMA1_Channel5,DMA_IT_TE,DISABLE);

NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);

USART1->CR3 |= (1<<6); //???DMA????
DMA_Cmd(DMA1_Channel5,ENABLE); //????DMA????

}

// void DMA1_Channel5_IRQHandler()
// {
// DMA_ClearFlag(DMA1_FLAG_TC5);
// int i;
// for(i=0;i<sizeof(USART1_RX_DMA_Buff);i++)
// printf("%c",USART1_RX_DMA_Buff[i]);
// printf("\r\n");
// }

static void read_uart_input_buff(void)
{
static int LastDataCount = 0;

//????????DMA��???.????DMA_GetCurrDataCounter?????????????????????.
int CurrDataCount = USART1_RX_DMA_BUFF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);

if(LastDataCount != CurrDataCount)
{
int i;
if(LastDataCount < CurrDataCount)
{
// printf("1:%d %d,",LastDataCount,CurrDataCount);
for(i = LastDataCount;i<CurrDataCount;i++) {
// MasterFrameInput(USART2_RX_DMA_Buff[i]);
printf("%c",USART1_RX_DMA_Buff[i]);
}
// printf("\r\n");
}
else
{
// printf("2:%d %d,",LastDataCount,CurrDataCount);
for(i = LastDataCount;i<USART1_RX_DMA_BUFF_SIZE;i++) {
// MasterFrameInput(USART2_RX_DMA_Buff[i]);
printf("%c",USART1_RX_DMA_Buff[i]);
}
for(i = 0;i<CurrDataCount;i++) {
// MasterFrameInput(USART2_RX_DMA_Buff[i]);
printf("%c",USART1_RX_DMA_Buff[i]);
}
// printf("\r\n");
}
}

LastDataCount = CurrDataCount;
}

static void SPI1_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO结构体变量
SPI_InitTypeDef SPI_InitStructure;

//初始化片选引脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

//chip select/reset pin init
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// SPI_CS = 1;
// SPI_RST = 1;

//初始化SPI引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//初始化SPI1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//复位SPI1
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1,&SPI_InitStructure);

SPI_SSOutputCmd(SPI1, ENABLE);
// SPI_Cmd(SPI1, DISABLE); //Enable SPI1

SPI_Cmd(SPI1, ENABLE); //Enable SPI1
// SPIx_ReadWriteByte(0xff); //启动传输
// SPI_Cmd(SPI1, DISABLE); //Enable SPI1
}

static void SPI2_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO结构体变量
SPI_InitTypeDef SPI_InitStructure;

//初始化片选引脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

//chip select/reset pin init
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// SPI_CS = 1;
// SPI_RST = 1;

//初始化SPI引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

//初始化SPI2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,ENABLE);//复位SPI2
RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,DISABLE);//停止复位SPI2

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2,&SPI_InitStructure);

SPI_SSOutputCmd(SPI2, DISABLE);
// SPI_Cmd(SPI2, DISABLE); //Enable SPI2

SPI_Cmd(SPI2, ENABLE); //Enable SPI2
// SPIx_ReadWriteByte(0xff); //启动传输
// SPI_Cmd(SPI2, DISABLE); //Enable SPI2

// SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);

NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = SPI2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);

}

void SPI2_IRQHandler()
{
if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) == SET) {
// SPI_I2S_ClearITPendingBit(SPI2, SPI_I2S_IT_RXNE);
LOGI("IRQ:%.2X\r\n", SPI2->DR);
}
}

static void SPI2_RX_DMA_Init(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

DMA_DeInit(DMA1_Channel4);

DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&SPI2->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (u32)SPI2_RX_DMA_Buff;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = sizeof(SPI2_RX_DMA_Buff);
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel4,&DMA_InitStruct);

DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,DISABLE);
DMA_ITConfig(DMA1_Channel4,DMA_IT_HT,DISABLE);
DMA_ITConfig(DMA1_Channel4,DMA_IT_TE,DISABLE);

NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);

SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);

DMA_Cmd(DMA1_Channel4,ENABLE); //????DMA????


}

void DMA1_Channel4_IRQHandler()
{
DMA_ClearFlag(DMA1_FLAG_TC4);
int i;
for(i=0;i<sizeof(SPI2_RX_DMA_Buff);i++)
printf("%c",SPI2_RX_DMA_Buff[i]);
printf("\r\n");
}

static void read_spi2_input_buff(void)
{
static int LastDataCount = 0;

int CurrDataCount = SPI2_RX_DMA_BUFF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel4);

if(LastDataCount != CurrDataCount)
{
int i;
if(LastDataCount < CurrDataCount)
{
// printf("1:%d %d,",LastDataCount,CurrDataCount);
for(i = LastDataCount;i<CurrDataCount;i++) {
// printf("%.2X ",SPI2_RX_DMA_Buff[i]);
SPI2_frame_handler(SPI2_RX_DMA_Buff[i]);
}
// printf("\r\n");
}
else
{
// printf("2:%d %d,",LastDataCount,CurrDataCount);
for(i = LastDataCount;i<SPI2_RX_DMA_BUFF_SIZE;i++) {
// printf("%.2X ",SPI2_RX_DMA_Buff[i]);
SPI2_frame_handler(SPI2_RX_DMA_Buff[i]);
}
for(i = 0;i<CurrDataCount;i++) {
// printf("%.2X ",SPI2_RX_DMA_Buff[i]);
SPI2_frame_handler(SPI2_RX_DMA_Buff[i]);
}
// printf("\r\n");
}
}

LastDataCount = CurrDataCount;
}

static void SPI2_frame_handler(uint8_t data)
{
// printf("%.2X\r\n", data);

static int state = 0;

// 0xA5 5A 55 AA
if (state == 0) {
if (data == 0xA5) {
state = 1;
}
} else if (state == 1) {
if (data == 0x5A) {
state = 2;
} else if (data == 0xA5) {

} else {
LOGE("Frame err\r\n");
while (1);
state = 0;
}
} else if (state == 2) {
if (data == 0x55) {
state = 3;
} else if (data == 0xA5) {
state = 1;
} else {
LOGE("Frame err\r\n");
while (1);
state = 0;
}
} else if (state == 3) {
if (data == 0xAA) {
state = 4;
} else if (data == 0xA5) {
state = 1;
} else {
LOGE("Frame err\r\n");
while (1);
state = 0;
}
} else if (state == 4) {
printf("ADDR:%.2X\r\n", data);
state = 5;
} else if (state == 5) {
printf("CMD:%.2X\r\n", data);
// SPI2->DR = 0x33;

DMA_Cmd(DMA1_Channel5, DISABLE); // disable DMA before starting a new DMA transaction

DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&SPI2->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (u32)SPI2_TX_DMA_Buff;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_BufferSize = sizeof(SPI2_TX_DMA_Buff);
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel5,&DMA_InitStruct);

DMA_Cmd(DMA1_Channel5, ENABLE);

state = 0;
} else if (state == 6) {

} else if (state == 7) {

} else if (state == 8) {

} else if (state == 9) {

} else if (state == 10) {

} else {

}
}

static void SPI2_TX_DMA_Init(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

DMA_DeInit(DMA1_Channel5);

DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&SPI2->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (u32)SPI2_TX_DMA_Buff;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_BufferSize = sizeof(SPI2_TX_DMA_Buff);
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel5,&DMA_InitStruct);

DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);
DMA_ITConfig(DMA1_Channel5,DMA_IT_HT,DISABLE);
DMA_ITConfig(DMA1_Channel5,DMA_IT_TE,DISABLE);

NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);

SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

DMA_Cmd(DMA1_Channel5,DISABLE); //????DMA????

// note: the last byte moved from RAM to SPI2->DR is seen as the end of DMA transmission
// but the last byte still not been transferred out from the shift register which means
// the SPI master might not received the last byte when the SPI slave finishing the DMA
// transfer.
}

void DMA1_Channel5_IRQHandler()
{
DMA_ClearFlag(DMA1_FLAG_TC5);
LOGI("Sent done\r\n");
DMA_Cmd(DMA1_Channel5, DISABLE);
SPI2->DR = 0x00; // set the shift register to 0x00 other wise SPI master will get the previous byte
// which might be 0xA0 and causes error.
}