Столкнулся со следующей проблемой, пытаюсь организовать передачу файла с компьютера на микроконтроллер STM32F4 при помощи uart и протокола xmodem1k.
Отправитель написан на java, сразу оговорюсь, написал на java также receiver, и передавал по xmodem1k файл на java, проблем никаких не было, стал писать приемщик на C под stm32 и заметил что, в какой-то момент данные в буфере смещаются.
Вот пример пакета, который шлет компьютер
Код
[b]2 1 -2[/b] -1 -40 -1 -32 0 16 74 70 73 70 0 1 1 1 0 1 0 1 0 0 -1 -37 0 67 0 . . . 233 [b]128 197[/b]
То есть первый байт я говорю, длину пакета (STX или SOH), второй байт - это номер пакета, 3 - инверсия номера пакета, далее данные по 128 или 1024 байта, последние два байта CRC16
И в какой-то момент я вижу что данные смещаются, например так
Код
[b]197 2 1[/b] -2 -1 -40 -1 -32 0 16 74 70 73 70 0 1 1 1 0 1 0 1 0 0 -1 -37 0 67 0 . . . [b]233 128[/b]
или даже так бывает
Код
[b]233 128 197[/b] 2 1 -2 -1 -40 -1 -32 0 16 74 70 73 70 0 1 1 1 0 1 0 1 0 0 -1 -37 0 67 0 . . .
То есть начало буфера получается в конце данных, при этом вроде как порядок байтов не меняется, то есть когда порядок начинается с 2 1 -2 ...
Я вижу, что CRC возвращает истину и пакет цел
Сначала думал, что проблема в отправители, но попробовал ставить паузу после отправки каждого байта все отправляет корректно, то есть я вижу последовательность байтов.
Еще такой момент, когда запускаю отладчик, и ставлю breakpoint на прием последнего байта, то получается чаще принимать данные в правильной последовательности.
То есть если запустить на плате прием данных, без прерывания отладчиком, то начинает зависать на втором пакете, всегда CRC не совпадает и программа отправляет NAK, а если поставить точку в отладчике, то с n раза пакет приходит в правильной последовательности и я сообщаю отправителю слать следующий пакет, иногда, конечно, приходит не в той последовательности, но в другой попытке - все приходит ровно. Но в отладчике также есть момент, когда в какой-то момент программа подвисает, то есть не дойдя до контрольной точки никак не реагирует, хотя отправитель послал пакет, либо после resume контрольной точки, не доходит до места отправки NAK или ACK, приходится хардверно отправлять NAK (на пользовательскую кнопку повешена такая задача)
Также пробовал перебирать последовательность принятых байт, смещая их на одну позицию назад, но это не очень удобно, если неизвестно на какой позиции находится настоящий первый элемент пакета.
Вот пример инициализации и приема данных в stm
Если, например, опустить дополнительные байты, а отправлять только данные, то все пакеты проходят, однако, там байты тоже сдвигаются, и, отправляя, например, картинку, в stm я вижу эту картинку, но видно, что в некоторых местах байты не на месте
CODE
void usart3_init(void)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
HAL_UART_Init(&huart3);
}
...
void interrupts_usart3_init(void)
{
HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 6, 1);
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
__HAL_UART_FLUSH_DRREGISTER(&huart3);
HAL_UART_Receive_DMA(&huart3, &rxBuffer, 1);
}
...
void dma_usart3_rx_init(void)
{
hdma_usart3_rx.Instance = DMA1_Stream1;
hdma_usart3_rx.Init.Channel = DMA_CHANNEL_4;
hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart3_rx.Init.MemInc = DMA_MINC_DISABLE;
hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart3_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart3_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_usart3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_usart3_rx);
__HAL_LINKDMA(&huart3, hdmarx, hdma_usart3_rx);
}
...
void DMA1_Stream1_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Stream1_IRQn);
HAL_DMA_IRQHandler(&hdma_usart3_rx);
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart3);
}
...
#define MAXCLISTRING 1029
uint8_t rxString[MAXCLISTRING];
uint8_t rxBuffer = 0;
uint8_t rxindex = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
__HAL_UART_FLUSH_DRREGISTER(&huart3); // Clear the buffer to prevent overrun
if (rxindex == MAXCLISTRING) // если конец пакета
{
rxindex = 0;
if (checkCRC16(&rxString[3], SIZE) == 1) // сравниваю контрольную сумму
{
led_toggle(BLUE);
xbuf[0] = ACK;
UINT* bw;
f_write(&fil, &rxString[3], SIZE, (UINT*)&bw);
if (bw > 0) led_toggle(ORANGE);
HAL_UART_Transmit(&huart3, xbuf, 1, 5); // сообщаю, что готов принять следующий пакет
}
else
{
xbuf[0] = NAK;
HAL_UART_Transmit(&huart3, xbuf, 1, 5); // прошу повторить пакет
}
}
else
{
rxString[rxindex] = rxBuffer; // записываю новый байт в буфер
rxindex++; // увеличиваю индекс
}
}
{
huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
HAL_UART_Init(&huart3);
}
...
void interrupts_usart3_init(void)
{
HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 6, 1);
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
__HAL_UART_FLUSH_DRREGISTER(&huart3);
HAL_UART_Receive_DMA(&huart3, &rxBuffer, 1);
}
...
void dma_usart3_rx_init(void)
{
hdma_usart3_rx.Instance = DMA1_Stream1;
hdma_usart3_rx.Init.Channel = DMA_CHANNEL_4;
hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart3_rx.Init.MemInc = DMA_MINC_DISABLE;
hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart3_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart3_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_usart3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_usart3_rx);
__HAL_LINKDMA(&huart3, hdmarx, hdma_usart3_rx);
}
...
void DMA1_Stream1_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Stream1_IRQn);
HAL_DMA_IRQHandler(&hdma_usart3_rx);
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart3);
}
...
#define MAXCLISTRING 1029
uint8_t rxString[MAXCLISTRING];
uint8_t rxBuffer = 0;
uint8_t rxindex = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
__HAL_UART_FLUSH_DRREGISTER(&huart3); // Clear the buffer to prevent overrun
if (rxindex == MAXCLISTRING) // если конец пакета
{
rxindex = 0;
if (checkCRC16(&rxString[3], SIZE) == 1) // сравниваю контрольную сумму
{
led_toggle(BLUE);
xbuf[0] = ACK;
UINT* bw;
f_write(&fil, &rxString[3], SIZE, (UINT*)&bw);
if (bw > 0) led_toggle(ORANGE);
HAL_UART_Transmit(&huart3, xbuf, 1, 5); // сообщаю, что готов принять следующий пакет
}
else
{
xbuf[0] = NAK;
HAL_UART_Transmit(&huart3, xbuf, 1, 5); // прошу повторить пакет
}
}
else
{
rxString[rxindex] = rxBuffer; // записываю новый байт в буфер
rxindex++; // увеличиваю индекс
}
}