Делаю на stm32f103 приемопередающую часть с обработчиком произвольных команд для посылок произвольной длины.
Сейчас код выглядит так (самое важное):
CODE
volatile uint8_t usart1_rx_buff[255];
volatile int32_t usart1_rx_buff_lenght = 0;
volatile int32_t usart1_rx_data_ready = 0;
volatile uint8_t usart1_tx_buff[255];
volatile int32_t usart1_tx_buff_lenght = 0;
void USART1_config (void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Enable clk APB2 -> GPIOA
GPIO_INIT_PIN(GPIOA,9,GPIO_MODE_OUTPUT50_ALT_PUSH_PULL); // USART1 PA9 TX
GPIO_INIT_PIN(GPIOA,10,GPIO_MODE_INPUT_FLOATING); // USART1 PA10 RX
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd((RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO), ENABLE); //Разрешаем тактирование
USART_InitStructure.USART_BaudRate = 115200;// скорость
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8 бит данных
USART_InitStructure.USART_StopBits = USART_StopBits_1; //один стоп бит
USART_InitStructure.USART_Parity = USART_Parity_No; //четность - нет
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // управлени потоком - нет
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // разрешаем прием и передачу
USART_Init(USART1, &USART_InitStructure); //инизиализируем
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //канал
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //приоритет
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//приоритет субгруппы
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //включаем канал
NVIC_Init(&NVIC_InitStructure); //инициализируем
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
USART_Cmd(USART1, ENABLE);
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // Receive Data register not empty interrupt
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
if(USART_GetITStatus(USART1, USART_IT_TC) != RESET) // Transmission complete interrupt
{
USART_ClearITPendingBit(USART1, USART_IT_TC);
}
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) // IDLE
{
USART_ClearITPendingBit(USART1, USART_IT_IDLE); // When DMA receiving get IDLE on UART
USART_ITConfig(USART1, USART_IT_IDLE, DISABLE); // Выключаем прерывание т.к. мы схуято тутже висим постоянно
usart1_rx_data_ready = 1;
}
}
void DMA_for_USART1_TX_config_and_run (uint8_t buff_size)
{
// Config DMA : usart1_tx_buff -> USART1 for 255 bytes
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (USART1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t) usart1_tx_buff;
DMA_InitStruct.DMA_BufferSize = buff_size;
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_Init(DMA1_Channel4, &DMA_InitStruct);
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
NVIC_EnableIRQ(DMA1_Channel4_IRQn);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel4, ENABLE); // RUN
_delay_us(10);
}
void DMA_for_USART1_RX_config_and_run (void)
{
// Config DMA : USART1 -> usart1_rx_buff for 255 bytes
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (USART1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t) usart1_rx_buff;
DMA_InitStruct.DMA_BufferSize = 255;
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_Init(DMA1_Channel5, &DMA_InitStruct);
NVIC_EnableIRQ(DMA1_Channel5_IRQn);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE); // RUN
}
void DMA1_Channel4_IRQHandler(void) // USART1 TX // Now ONLY transfer complete
{
DMA_Cmd(DMA1_Channel4, DISABLE);
USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);
if(DMA1->ISR & DMA_ISR_TCIF4) // Если обмен завершен
{
DMA_ClearITPendingBit(DMA1_IT_TC4);
}
if(DMA1->ISR & DMA_ISR_HTIF4) // Если передана половина буфера
{
DMA_ClearITPendingBit(DMA1_IT_HT4);
}
if(DMA1->ISR & DMA_ISR_TEIF4) // Если произошла ошибка при обмене
{
DMA_ClearITPendingBit(DMA1_IT_TE4);
}
if(DMA1->ISR & DMA_ISR_GIF4) // Если произошла ошибка при обмене
{
DMA_ClearITPendingBit(DMA_ISR_GIF4);
}
}
void DMA1_Channel5_IRQHandler(void) // USART1 RX // Now ONLY transfer complete
{
DMA_Cmd(DMA1_Channel5, DISABLE);
USART_DMACmd(USART1, USART_DMAReq_Rx, DISABLE);
if(DMA1->ISR & DMA_ISR_TCIF5) // Если обмен завершен
{
DMA_ClearITPendingBit(DMA1_IT_TC5);
}
if(DMA1->ISR & DMA_ISR_HTIF5) // Если передана половина буфера
{
DMA_ClearITPendingBit(DMA1_IT_HT5);
}
if(DMA1->ISR & DMA_ISR_TEIF5) // Если произошла ошибка при обмене
{
DMA_ClearITPendingBit(DMA1_IT_TE5);
}
if(DMA1->ISR & DMA_ISR_GIF5) // Если произошла глобальная ошибка
{
DMA_ClearITPendingBit(DMA_ISR_GIF5);
}
}
void Execute_Command (void)
{
if (usart1_rx_data_ready == 1) //
{
usart1_rx_data_ready = 0;
DMA_Cmd(DMA1_Channel5, DISABLE); // Stop DMA
usart1_rx_buff_lenght = 255 - DMA_GetCurrDataCounter(DMA1_Channel5); // Get REMAINING counter for work with usart1_rx_buff
// Data in "usart1_rx_buff" & len of it "usart1_rx_buff_lenght" READY
if (usart1_rx_buff_lenght != 0)
{
// Func FN01 "Echo" ***************************************************************************
*************************
//if ((usart1_rx_buff[0]=='F')&(usart1_rx_buff[1]=='N')&(usart1_rx_buff[2]=='0')&(usart1_rx_buff[3]=='1'))
//{
//GPIOB->BSRR = GPIO_BSRR_BS5; vTaskDelay(100); GPIOB->BSRR = GPIO_BSRR_BR5; vTaskDelay(100); // For DEBUG
usart1_tx_buff_lenght = usart1_rx_buff_lenght;
for (usart1_rx_buff_lenght; usart1_rx_buff_lenght>=0; usart1_rx_buff_lenght--)
{
usart1_tx_buff[usart1_rx_buff_lenght] = usart1_rx_buff[usart1_rx_buff_lenght];
};
DMA_for_USART1_TX_config_and_run(usart1_tx_buff_lenght);
//}
}
// Remain of listening
DMA_for_USART1_RX_config_and_run();
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
}
}
int main(void)
{
System_RCC_config();
GPIO_config();
USART1_config();
DMA_for_USART1_RX_config_and_run();
TIM3_PWM_config_and_run();
xTaskCreate( default_task, ( signed char * ) "default_task", configMINIMAL_STACK_SIZE, NULL, 1, NULL );
__enable_irq ();
vTaskStartScheduler();
while(1){}
}
void default_task ( void *pvParameters )
{
for(;; )
{
vTaskDelay(1);
Execute_Command();
}
vTaskDelete( NULL );
}
volatile int32_t usart1_rx_buff_lenght = 0;
volatile int32_t usart1_rx_data_ready = 0;
volatile uint8_t usart1_tx_buff[255];
volatile int32_t usart1_tx_buff_lenght = 0;
void USART1_config (void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Enable clk APB2 -> GPIOA
GPIO_INIT_PIN(GPIOA,9,GPIO_MODE_OUTPUT50_ALT_PUSH_PULL); // USART1 PA9 TX
GPIO_INIT_PIN(GPIOA,10,GPIO_MODE_INPUT_FLOATING); // USART1 PA10 RX
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd((RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO), ENABLE); //Разрешаем тактирование
USART_InitStructure.USART_BaudRate = 115200;// скорость
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8 бит данных
USART_InitStructure.USART_StopBits = USART_StopBits_1; //один стоп бит
USART_InitStructure.USART_Parity = USART_Parity_No; //четность - нет
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // управлени потоком - нет
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // разрешаем прием и передачу
USART_Init(USART1, &USART_InitStructure); //инизиализируем
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //канал
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //приоритет
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//приоритет субгруппы
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //включаем канал
NVIC_Init(&NVIC_InitStructure); //инициализируем
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
USART_Cmd(USART1, ENABLE);
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // Receive Data register not empty interrupt
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
if(USART_GetITStatus(USART1, USART_IT_TC) != RESET) // Transmission complete interrupt
{
USART_ClearITPendingBit(USART1, USART_IT_TC);
}
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) // IDLE
{
USART_ClearITPendingBit(USART1, USART_IT_IDLE); // When DMA receiving get IDLE on UART
USART_ITConfig(USART1, USART_IT_IDLE, DISABLE); // Выключаем прерывание т.к. мы схуято тутже висим постоянно
usart1_rx_data_ready = 1;
}
}
void DMA_for_USART1_TX_config_and_run (uint8_t buff_size)
{
// Config DMA : usart1_tx_buff -> USART1 for 255 bytes
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (USART1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t) usart1_tx_buff;
DMA_InitStruct.DMA_BufferSize = buff_size;
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_Init(DMA1_Channel4, &DMA_InitStruct);
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
NVIC_EnableIRQ(DMA1_Channel4_IRQn);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel4, ENABLE); // RUN
_delay_us(10);
}
void DMA_for_USART1_RX_config_and_run (void)
{
// Config DMA : USART1 -> usart1_rx_buff for 255 bytes
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (USART1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t) usart1_rx_buff;
DMA_InitStruct.DMA_BufferSize = 255;
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_Init(DMA1_Channel5, &DMA_InitStruct);
NVIC_EnableIRQ(DMA1_Channel5_IRQn);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE); // RUN
}
void DMA1_Channel4_IRQHandler(void) // USART1 TX // Now ONLY transfer complete
{
DMA_Cmd(DMA1_Channel4, DISABLE);
USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);
if(DMA1->ISR & DMA_ISR_TCIF4) // Если обмен завершен
{
DMA_ClearITPendingBit(DMA1_IT_TC4);
}
if(DMA1->ISR & DMA_ISR_HTIF4) // Если передана половина буфера
{
DMA_ClearITPendingBit(DMA1_IT_HT4);
}
if(DMA1->ISR & DMA_ISR_TEIF4) // Если произошла ошибка при обмене
{
DMA_ClearITPendingBit(DMA1_IT_TE4);
}
if(DMA1->ISR & DMA_ISR_GIF4) // Если произошла ошибка при обмене
{
DMA_ClearITPendingBit(DMA_ISR_GIF4);
}
}
void DMA1_Channel5_IRQHandler(void) // USART1 RX // Now ONLY transfer complete
{
DMA_Cmd(DMA1_Channel5, DISABLE);
USART_DMACmd(USART1, USART_DMAReq_Rx, DISABLE);
if(DMA1->ISR & DMA_ISR_TCIF5) // Если обмен завершен
{
DMA_ClearITPendingBit(DMA1_IT_TC5);
}
if(DMA1->ISR & DMA_ISR_HTIF5) // Если передана половина буфера
{
DMA_ClearITPendingBit(DMA1_IT_HT5);
}
if(DMA1->ISR & DMA_ISR_TEIF5) // Если произошла ошибка при обмене
{
DMA_ClearITPendingBit(DMA1_IT_TE5);
}
if(DMA1->ISR & DMA_ISR_GIF5) // Если произошла глобальная ошибка
{
DMA_ClearITPendingBit(DMA_ISR_GIF5);
}
}
void Execute_Command (void)
{
if (usart1_rx_data_ready == 1) //
{
usart1_rx_data_ready = 0;
DMA_Cmd(DMA1_Channel5, DISABLE); // Stop DMA
usart1_rx_buff_lenght = 255 - DMA_GetCurrDataCounter(DMA1_Channel5); // Get REMAINING counter for work with usart1_rx_buff
// Data in "usart1_rx_buff" & len of it "usart1_rx_buff_lenght" READY
if (usart1_rx_buff_lenght != 0)
{
// Func FN01 "Echo" ***************************************************************************
*************************
//if ((usart1_rx_buff[0]=='F')&(usart1_rx_buff[1]=='N')&(usart1_rx_buff[2]=='0')&(usart1_rx_buff[3]=='1'))
//{
//GPIOB->BSRR = GPIO_BSRR_BS5; vTaskDelay(100); GPIOB->BSRR = GPIO_BSRR_BR5; vTaskDelay(100); // For DEBUG
usart1_tx_buff_lenght = usart1_rx_buff_lenght;
for (usart1_rx_buff_lenght; usart1_rx_buff_lenght>=0; usart1_rx_buff_lenght--)
{
usart1_tx_buff[usart1_rx_buff_lenght] = usart1_rx_buff[usart1_rx_buff_lenght];
};
DMA_for_USART1_TX_config_and_run(usart1_tx_buff_lenght);
//}
}
// Remain of listening
DMA_for_USART1_RX_config_and_run();
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
}
}
int main(void)
{
System_RCC_config();
GPIO_config();
USART1_config();
DMA_for_USART1_RX_config_and_run();
TIM3_PWM_config_and_run();
xTaskCreate( default_task, ( signed char * ) "default_task", configMINIMAL_STACK_SIZE, NULL, 1, NULL );
__enable_irq ();
vTaskStartScheduler();
while(1){}
}
void default_task ( void *pvParameters )
{
for(;; )
{
vTaskDelay(1);
Execute_Command();
}
vTaskDelete( NULL );
}
В таком виде конкретно функция Execute_Command которая умеет ЭХО делает всё быстро и замечательно. На все скорости ни затыков ничего такого.
Однако когда Я раскомментирую условие "if ((usart1_rx_buff[0]=='F')&(usart1_rx_buff[1]=='N')&(usart1_rx_buff[2]=='0')&(usart1_rx_buff[3]=='1'))" начинается дичь, а именно в случайном порядке пришедший ответ короче с конца на случайное число байт.
А когда Я раскомментирую мигание светодиодиком (for debug) через несколько срабатываний фукнция перестаёт вообще чтолибо делать, т.к. приемный счётчик DMA1_Channel4 возвращает 255.
Причем еще Я использую обработку IDLE флага от USART, перечитав даташит несколько раз всеравно не могу понять - может ли он корректно поймать тишину после байта? Но как видно - работает.
Это мой первый опыт такого конфигурирования и в целом Я не очень хороший программист, возможно кто-нибудь свежим взглядом найдет ошибку и подскажет как сделать лучше.
Надеюсь на вашу помощь.