где косяк
В DMA, после первого же переполнения буфера.
Попробуй настраивать буфер как CIRC
Микроконтроллеры |
Привет, Гость! Войдите или зарегистрируйтесь.
Вы здесь » Микроконтроллеры » Архив » STM32 UART
где косяк
В DMA, после первого же переполнения буфера.
Попробуй настраивать буфер как CIRC
В DMA, после первого же переполнения буфера.
Всмысле это "железная" проблема? В еррате про это ни слова..
Попробуй настраивать буфер как CIRC
Пробую
а отсутствие начальной инициализации переменных (например типа answer_len ) не может привести к такому эффекту ?
Похоже на гонку периферии... Лень всматриваться и вчитываться... Подобное происходит и на связке ТИМ+ДМА... так что дело не в железе... Отслеживайте флаги и порядок включения ЮАРТ и ДМА...
а отсутствие начальной инициализации переменных (например типа answer_len ) не может привести к такому эффекту ?
Они в .bss находятся, то есть содержат 0.
Файл kontr.map
.bss.answer_len 0x200006d4 0x1 Output/kontr Debug/Obj/modbus_master.o 0x200006d4 answer_len
Похоже на гонку периферии... Лень всматриваться и вчитываться... Подобное происходит и на связке ТИМ+ДМА... так что дело не в железе... Отслеживайте флаги и порядок включения ЮАРТ и ДМА...
Похоже, но результат стабильный, я как и раньше принимаю на 1 байт больше, а нулевой выкидываю, на тесте 2 часа, ни одного сбоя.
До этого пробовал по разному..
Похоже, но результат стабильный, я как и раньше принимаю на 1 байт больше, а нулевой выкидываю, на тесте 2 часа, ни одного сбоя.
До этого пробовал по разному..
"Это несерьёзно"
Так разгадки не будет что ли? )
sobs написал(а):
Похоже, но результат стабильный, я как и раньше принимаю на 1 байт больше, а нулевой выкидываю, на тесте 2 часа, ни одного сбоя.
До этого пробовал по разному.."Это несерьёзно"
Так разгадки не будет что ли? )
Может и будет, если додумаюсь) Пока идеи кончились.
Попробуй просто завести большой CIRC буфер, не делать никакой обработки (никаких прерываний по приёму, ну или пустышки) и посмотреть как туда пакеты от слейва ложатся, будет ли лишний байтик между пакетами
Попробуй просто завести большой CIRC буфер, не делать никакой обработки (никаких прерываний по приёму, ну или пустышки) и посмотреть как туда пакеты от слейва ложатся, будет ли лишний байтик между пакетами
Завтра буду на работе попробую, пока форумы читаю. Не я один такой, но другие используют hal и spl. Как найду решение - напишу.
У меня при передаче по ДМА была проблема что не доходил последний байт. Прерывание ДМА о завершении транзакции наступает тогда, когда в сдвиговый регистр поступает последний байт, ну я там же по дурости и переключал драйвер RS485 на прием. Потом уже когда понял в чем проблема в этом прерывании настраивал прерывание USART на окончание передачи, а там уже переключал драйвер RS485.
У меня при передаче по ДМА была проблема что не доходил последний байт. Прерывание ДМА о завершении транзакции наступает тогда, когда в сдвиговый регистр поступает последний байт, ну я там же по дурости и переключал драйвер RS485 на прием. Потом уже когда понял в чем проблема в этом прерывании настраивал прерывание USART на окончание передачи, а там уже переключал драйвер RS485.
Это у меня учтено. Логическим анализатором смотрел - все чисто)
sobs А я что-то в void MODBUS_Master_Send(_modbus_request modbus) не вижу где начало отправки
sobs А я что-то в void MODBUS_Master_Send(_modbus_request modbus) не вижу где начало отправки
USART3 -> CR1 |= USART_CR1_TXEIE;
Этим разрешаем прерывание по TXE, так как буфер USARTа пуст, то сразу срабатывает прерывание по TXE, а там уже
if (USART3 -> SR & USART_SR_TXE){ if (send_counter){ USART3 -> DR = *pointer++; send_counter--; } else { USART3 -> CR1 &= ~(USART_CR1_TXEIE); } }
Ты же по ДМА передаешь?
Ты же по ДМА передаешь?
Нет, принимаю по ДМА. Запросы короткие, а вот ответы..
Отредактировано sobs (2017-08-21 18:44:46)
sobs Я не нашел функцию приема, а как конец пакета отслеживаешь?
sobs
void Cl_USART_DMA::Read(uint8_t *RxBuff, uint16_t tCnt) { RxCnt = 0; DMA_Rx_Stream->CCR &= ~(DMA_CCR1_EN | DMA_CCR1_TCIE); // отключили канал ПДП Rx Rx_Stream_Clr_IFCR(); // сбросили все флаги прерываний DMA_Rx_Stream->CPAR = (uint32_t) &USART->DR; DMA_Rx_Stream->CMAR = (uint32_t) RxBuff; DMA_Rx_Stream->CNDTR = tCnt; DMA_Rx_Stream->CCR |= (DMA_CCR1_EN | DMA_CCR1_TCIE); USART->CR1 |= USART_CR1_IDLEIE | USART_CR1_RE; // включили приемник + IDLE детектор }
немного убрал лишнего, вот мой прием
Вот, когда я полностью отправил запрос, срабатывает прерывание USART_TC
if (USART3 -> SR & USART_SR_TC){ USART3 -> SR = ~(USART_SR_TC); //Переводим PHY в режим приемника DIR_LOW; //Включаем таймер (таймаут) TIM4 -> CR1 |= TIM_CR1_CEN; //Настраиваем ДМА для приема пакета DMA1_Channel3 -> CCR &= ~(DMA_CCR1_EN); DMA1_Channel3 -> CMAR = (uint32_t)answ_buf; DMA1_Channel3 -> CNDTR = answer_len; DMA1_Channel3 -> CCR |= DMA_CCR1_EN; }
Далее есть 2 варианта, либо пакет придет (сработает прерывание по DMA), либо нет (сработает прерывание по таймауту TIM4).
Если пакет пришел
void DMA1_Channel3_IRQHandler(){ uint16_t crc; //сбрасываем флаг прерывания, останавливаем и сбрасываем таймер, выключаем ДМА DMA1 -> IFCR |= DMA_IFCR_CTCIF3; TIM4 -> CNT = 0; TIM4 -> CR1 &= ~(TIM_CR1_CEN); DMA1_Channel3 -> CCR &= ~(DMA_CCR1_EN); //Проверка контрольной суммы crc = crc_chk(answ_buf, answer_len - 2); if (crc == (answ_buf[answer_len - 2] | (answ_buf[answer_len - 1] << 8))){ //ОК stat.modbus_error = 0; } else { //Не ОК stat.modbus_error = 1; } stat.modbus_busy = 0; }
Таймаут
void TIM4_IRQHandler(){ TIM4 -> SR = ~(TIM_SR_UIF); stat.modbus_busy = 0; stat.modbus_error = 1; DMA1_Channel3 -> CCR &= ~(DMA_CCR1_EN); }
USART_CR1_IDLEIE
А что в IDLE делаешь?
sobs У меня поток 100% плотный, это определение конца пакета время = 1.5 байта. А когда по ДМА прерывание это переполнение буфера. (длина буфера +1 от максимально возможного). Перед включением канала ДМА, сбрасывай все флаги канала ДМА!!! у меня были проблемы с этим, но точно уже не помню как они проявлялись. И перед включением посмотри что в статусе USART может там флаг поднят и он сразу принимает старый байт, это самое очевидное что пришло в голову)
Отредактировано MasterElectric (2017-08-21 19:19:12)
В общем разгадка такова:
1. Инициализирую USART, но не устанавливаю бит USART_CR3_DMAR.
2. После запуска ДМА на прием пакета чищу регистр статуса USART и устанавливаю USART_CR3_DMAR:
DMA1_Channel3 -> CCR &= ~(DMA_CCR1_EN); DMA1_Channel3 -> CNDTR = answer_len; DMA1_Channel3 -> CCR |= DMA_CCR1_EN; USART3 -> SR = 0; USART3 -> CR3 = USART_CR3_DMAR;
3. После выключения ДМА, сбрасываю бит USART_CR3_DMAR.
DMA1_Channel3 -> CCR &= ~(DMA_CCR1_EN); USART3 -> CR3 = 0;
Если сделать так, то байты ложатся на свое место.
sobs USART3 -> CR3 = USART_CR3_DMAR; делать после включения канала ДМА очень логичное решение, переделаю у себя тоже. Потому как если сделать запрос каналу ДМА, то его уже проблематично сбросить, я вроде бы находил где, но уже не помню, но скроее всего я тоже выкручивался как-то подобным способом, но работал с каналами таймера.
Всё хорошо, что хорошо кончается )
А теперь представим себе (чисто гипотетически, я не призываю так делать) - SysTick 12 КГц, четыре флажка (TXE, TC, RXNE, IDLE) и регистр DR, никаких доп прерываний, никаких DMA - как всё стало бы просто и естественно )
vt340 Все от задачи зависит, я вот делаю прием до 2 Мбит, да и процессор всегда есть чем занять)
как всё стало бы просто и естественно
STC?
Кстати при приеме по ДМА для расчета количества принятых байт нужно от первоначального значения NDTR отнять то что осталось в NDTR после окончания приема, в модуле ДМА.
STC?
YAGNI )
USART3 -> CR3 = USART_CR3_DMAR; делать после включения канала ДМА очень логичное решение, переделаю у себя тоже. Потому как если сделать запрос каналу ДМА, то его уже проблематично сбросить, я вроде бы находил где, но уже не помню, но скроее всего я тоже выкручивался как-то подобным способом, но работал с каналами таймера.
Уверен... что это не единственный вариант решения... А ваще... тестовые пины и логанализатор в таких ситуациях рулят...
Всё хорошо, что хорошо кончается )
А теперь представим себе (чисто гипотетически, я не призываю так делать) - SysTick 12 КГц, четыре флажка (TXE, TC, RXNE, IDLE) и регистр DR, никаких доп прерываний, никаких DMA - как всё стало бы просто и естественно )
Как по мне... ничего простого... и ничего естественного... даже наоборот... какое-то горе от ума...
Вы здесь » Микроконтроллеры » Архив » STM32 UART