Микроконтроллеры

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Микроконтроллеры » STM32: USART, I2C, USB » UART


UART

Сообщений 31 страница 60 из 63

31

sobs написал(а):

где косяк

В DMA, после первого же переполнения буфера.
Попробуй настраивать буфер как CIRC

32

vt340 написал(а):

В DMA, после первого же переполнения буфера.

Всмысле это "железная" проблема? В еррате про это ни слова..

vt340 написал(а):

Попробуй настраивать буфер как CIRC

Пробую

33

vt340 написал(а):

Попробуй настраивать буфер как CIRC

Попробовал, сдвиг остался, но вместо нуля в нулевом байте - последний байт контрольной суммы.
http://s3.uploads.ru/t/LAxOh.png

Отредактировано sobs (2017-08-21 11:50:25)

34

а отсутствие начальной инициализации переменных (например типа answer_len ) не может привести к такому эффекту ?

35

Похоже на гонку периферии... Лень всматриваться и вчитываться... Подобное происходит и на связке ТИМ+ДМА... так что дело не в железе... Отслеживайте флаги и порядок включения ЮАРТ и ДМА...

36

Atomic-dm написал(а):

а отсутствие начальной инициализации переменных (например типа answer_len ) не может привести к такому эффекту ?

Они в .bss находятся, то есть содержат 0.
Файл kontr.map

Код:
 .bss.answer_len
                0x200006d4        0x1 Output/kontr Debug/Obj/modbus_master.o
                0x200006d4                answer_len
HHIMERA написал(а):

Похоже на гонку периферии... Лень всматриваться и вчитываться... Подобное происходит и на связке ТИМ+ДМА... так что дело не в железе... Отслеживайте флаги и порядок включения ЮАРТ и ДМА...

Похоже, но результат стабильный, я как и раньше принимаю на 1 байт больше, а нулевой выкидываю, на тесте 2 часа, ни одного сбоя.
До этого пробовал по разному..

37

sobs написал(а):

Похоже, но результат стабильный, я как и раньше принимаю на 1 байт больше, а нулевой выкидываю, на тесте 2 часа, ни одного сбоя.
До этого пробовал по разному..

"Это несерьёзно"
Так разгадки не будет что ли? )

38

vt340 написал(а):

sobs написал(а):

    Похоже, но результат стабильный, я как и раньше принимаю на 1 байт больше, а нулевой выкидываю, на тесте 2 часа, ни одного сбоя.
    До этого пробовал по разному..

"Это несерьёзно"
Так разгадки не будет что ли? )

Может и будет, если додумаюсь) Пока идеи кончились.

39

Попробуй просто завести большой CIRC буфер, не делать никакой обработки (никаких прерываний по приёму, ну или пустышки) и посмотреть как туда пакеты от слейва ложатся, будет ли лишний байтик между пакетами

40

vt340 написал(а):

Попробуй просто завести большой CIRC буфер, не делать никакой обработки (никаких прерываний по приёму, ну или пустышки) и посмотреть как туда пакеты от слейва ложатся, будет ли лишний байтик между пакетами

Завтра буду на работе попробую, пока форумы читаю. Не я один такой, но другие используют hal и spl. Как найду решение - напишу.

41

У меня при передаче по ДМА была проблема что не доходил последний байт. Прерывание ДМА о завершении транзакции наступает тогда, когда в сдвиговый регистр поступает последний байт, ну я там же по дурости и переключал драйвер RS485 на прием. Потом уже когда понял в чем проблема в этом прерывании настраивал прерывание USART на окончание передачи, а там уже переключал драйвер RS485.

42

MasterElectric написал(а):

У меня при передаче по ДМА была проблема что не доходил последний байт. Прерывание ДМА о завершении транзакции наступает тогда, когда в сдвиговый регистр поступает последний байт, ну я там же по дурости и переключал драйвер RS485 на прием. Потом уже когда понял в чем проблема в этом прерывании настраивал прерывание USART на окончание передачи, а там уже переключал драйвер RS485.

Это у меня учтено. Логическим анализатором смотрел - все чисто)

43

sobs А я что-то в void MODBUS_Master_Send(_modbus_request modbus) не вижу где начало отправки

44

MasterElectric написал(а):

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);
	}
    } 

45

Ты же по ДМА передаешь?

46

MasterElectric написал(а):

Ты же по ДМА передаешь?

Нет, принимаю по ДМА. Запросы короткие, а вот ответы..

Отредактировано sobs (2017-08-21 18:44:46)

47

sobs Я не нашел функцию приема, а как конец пакета отслеживаешь?

48

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 детектор
}

немного убрал лишнего, вот мой прием

49

Вот, когда я полностью отправил запрос, срабатывает прерывание 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);
}

50

MasterElectric написал(а):

USART_CR1_IDLEIE

А что в IDLE делаешь?

51

sobs У меня поток 100% плотный, это определение конца пакета время = 1.5 байта. А когда по ДМА прерывание это переполнение буфера. (длина буфера +1 от максимально возможного). Перед включением канала ДМА, сбрасывай все флаги канала ДМА!!! у меня были проблемы с этим, но точно уже не помню как они проявлялись. И перед включением посмотри что в статусе USART может там флаг поднят и он сразу принимает старый байт, это самое очевидное что пришло в голову)

Отредактировано MasterElectric (2017-08-21 19:19:12)

52

В общем разгадка такова:
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;

Если сделать так, то байты ложатся на свое место.

53

sobs USART3 -> CR3 = USART_CR3_DMAR; делать после включения канала ДМА очень логичное решение, переделаю у себя тоже. Потому как если сделать запрос каналу ДМА, то его уже проблематично сбросить, я вроде бы находил где, но уже не помню, но скроее всего я тоже выкручивался как-то подобным способом, но работал с каналами таймера.

54

Всё хорошо, что хорошо кончается )
А теперь представим себе (чисто гипотетически, я не призываю так делать) - SysTick 12 КГц, четыре флажка (TXE, TC, RXNE, IDLE) и регистр DR, никаких доп прерываний, никаких DMA - как всё стало бы просто и естественно )

55

vt340 Все от задачи зависит, я вот делаю прием до 2 Мбит, да и процессор всегда есть чем занять)

56

vt340 написал(а):

как всё стало бы просто и естественно


STC?

57

Кстати при приеме по ДМА для расчета количества принятых байт нужно от первоначального значения NDTR отнять то что осталось в NDTR после окончания приема, в модуле ДМА.

58

dosikus написал(а):

STC?

YAGNI )

59

USART3 -> CR3 = USART_CR3_DMAR; делать после включения канала ДМА очень логичное решение, переделаю у себя тоже. Потому как если сделать запрос каналу ДМА, то его уже проблематично сбросить, я вроде бы находил где, но уже не помню, но скроее всего я тоже выкручивался как-то подобным способом, но работал с каналами таймера.

Уверен... что это не единственный вариант решения... А ваще... тестовые пины и логанализатор в таких ситуациях рулят...

60

Всё хорошо, что хорошо кончается )
А теперь представим себе (чисто гипотетически, я не призываю так делать) - SysTick 12 КГц, четыре флажка (TXE, TC, RXNE, IDLE) и регистр DR, никаких доп прерываний, никаких DMA - как всё стало бы просто и естественно )

Как по мне... ничего простого... и ничего естественного... даже наоборот... какое-то горе от ума...


Вы здесь » Микроконтроллеры » STM32: USART, I2C, USB » UART