Перейти к содержанию
    

STM32F103 USAR3 обмен по ModBus

Доброго времени суток всем.

Столкнулся с непонятным явлением

USART сконфигурированный с одними параметрами связи, отвечает на запросы с другими параметрами связи

Куда копать уже не знаю

Ни кто не сталкивался с подобным?

Modbus RTU Scaner.jpg

Изменено пользователем zaicev_ekb

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, zaicev_ekb said:

Ни кто не сталкивался с подобным?

Логический анализатор на линии? Всё покажет сразу.

1 hour ago, zaicev_ekb said:

Куда копать уже не знаю

Только на уровень физики и канала (по модели OSI);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, zaicev_ekb сказал:

Куда копать уже не знаю

В сторону обработки ошибок по приему, например. Биты данных во всех посылках совпадают, биты четности для приемника с отключенной проверкой четности должны вызывать ошибку приема стопового бита (framing error). В вышей программе эта ошибка, вероятно, не обрабатывается. А поскольку биты данных во всех форматах совпадают - посылка принимается правильно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

29 minutes ago, Сергей Борщ said:

В сторону обработки ошибок по приему, например. Биты данных во всех посылках совпадают, биты четности для приемника с отключенной проверкой четности должны вызывать ошибку приема стопового бита (framing error). В вышей программе эта ошибка, вероятно, не обрабатывается. А поскольку биты данных во всех форматах совпадают - посылка принимается правильно.

Спасибо за волщебный пендель

буду копать

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 7/7/2020 at 10:09 AM, haker_fox said:

Логический анализатор на линии? Всё покажет сразу.

Только на уровень физики и канала (по модели OSI);

Сергей вопрос в продолжение

Конфиг USART

 

    rs485_data.delay = br9600_timeout;
    USART_InitStructure.USART_BaudRate = br9600;
    USART_InitStructure.USART_WordLength          = USART_WordLength_9b;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_Parity              = USART_Parity_Even;     
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;
    
    USART_Init ( USART1, &USART_InitStructure );
    
    USART1->CR1 |= ( 1 << 10 ) | ( 1 << 8 );
    
    USART_ITConfig ( USART1, USART_IT_RXNE, ENABLE );
    USART_ITConfig ( USART1, USART_IT_NE, ENABLE );
    USART_ITConfig ( USART1, USART_IT_FE, ENABLE );
    USART_ITConfig ( USART1, USART_IT_ERR, ENABLE );

обработка прерывания

 

    if ( USART_GetITStatus ( USART1, USART_IT_RXNE ) != RESET ) {
        USART_ClearITPendingBit ( USART1, USART_IT_RXNE );
        
        rs485_data.rxtimer = 0;
        if ( rs485_data.rxcnt - 2 > ( RX_BUF_SIZE ) ) {
            rs485_data.rxcnt = 0;
        }
        rs485_data.buffer_rx[rs485_data.rxcnt] =  USART1->DR & (uint16_t)0x01FF;
        
        rs485_data.rxcnt++;
        rs485_data.symbol_first = 1;
        rs485_data.rxtimer = rs485_data.delay ;
    }
    
    if ( USART_GetITStatus ( USART1, USART_IT_TC ) != RESET ) {
        USART_ClearITPendingBit ( USART1, USART_IT_TC );
        rs485_dir_off();
        rs485_data.txend = 0;
        USART_ITConfig ( USART1, USART_IT_TC, DISABLE );
        rs485_data.Status_Tx = Tx_End;
    }
    
    if ( USART_GetITStatus ( USART1, USART_IT_TXE ) != RESET ) {
        USART_ClearITPendingBit ( USART1, USART_IT_TXE );
        
    }
    
    if ( USART_GetITStatus ( USART1, USART_IT_LBD ) != RESET ) {
        USART_ClearITPendingBit ( USART1, USART_IT_LBD );
        rs485_data.Status_Rx = Rx_Error;
    }
    
    if ( USART_GetITStatus ( USART1, USART_IT_ORE  ) != RESET ) {
        USART_ClearITPendingBit ( USART1, USART_IT_ORE  );
        rs485_data.Status_Rx = Rx_Error;
        rs485_data.buffer_rx[rs485_data.rxcnt] = USART_ReceiveData ( USART1 );
        rs485_data.rxcnt++;
    }
    
    if ( USART_GetITStatus ( USART1, USART_IT_FE ) != RESET ) {
        USART_ClearITPendingBit ( USART1, USART_IT_FE );
        USART_ClearITPendingBit ( USART1, USART_IT_PE );
        rs485_data.Status_Rx = Rx_Error;
        rs485_data.symbol_first = 0;
    }
    
    if ( USART_GetITStatus ( USART1, USART_IT_PE ) != RESET ) {
        USART_ClearITPendingBit ( USART1, USART_IT_PE );
        rs485_data.Status_Rx = Rx_Error;
        rs485_data.symbol_first = 0;
    }

При приеме байта в прерывание заходим но соответсвующий флаг PE не выставляется в регистре SR не выставляется

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, zaicev_ekb сказал:

но соответсвующий флаг PE в регистре SR не выставляется

Не выставляется или вы не попадаете в последнее условие, потому что флаг сбрасывается после чтения SR и DR в первом условии? Полагаю, что все же второе. Я не знаком с кубом, но внимательно читаю документацию на контроллер и его регистры. Из этой документации становится понятно, что ваш обработчик написан неправильно:

1) Нужно один раз в начале обработчика считать регистр статуса и потом во всех условиях работать со считанным значением, а не теребить SR при проверке каждого флага, как это делают недалекие авторы куба.

2) Многие биты в этом регистре сбрасываются автоматически чтением DR после чтения SR и вызов USART_ClearITPendingBit на них никоим образом не влияет.

Читайте справочное руководство (reference manual) на контроллер, а не только названия функций в кубе.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Сергей Борщ said:

как это делают недалекие авторы куба

О, а я не один) Но ругают на форуме почему-то только меня за то, что я ругаю куб))) Хотя, может быть и вам доставалось)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 минут назад, haker_fox сказал:

О, а я не один) Но ругают на форуме почему-то только меня за то, что я ругаю куб))) Хотя, может быть и вам доставалось)

Да на этот "исходник" без слёз смотреть невозможно!  :cray2:

До чего доводит кубокодерство, что простейший ISR так обезобразить позволяет. :shok:

А ведь там всего-то ничего нужно (для этого самого "народного" F103):

__no_init struct {
  char tx[200];
  char rx[80];
} static bufService @ ".dma";

u8 volatile rxw = 0, rxr = 0;
static OsFlag txNoFull = OS_FLAG_STATE_RESET, rxNoEmpty = OS_FLAG_STATE_RESET;

extern "C" void concat(isrUART, nUART_serv)()
{
  uint c, i0, i1, i2;
  HwRegsUART volatile *io = &concat(UART, nUART_serv);
  if ((i0 = io->SR) & (1 << UART_SR_NE | 1 << UART_SR_FE)) c = io->DR;
  else if (i0 & 1 << UART_SR_RXNE) {
    c = io->DR;
    if (i0 & (1 << UART_SR_PE | 1 << UART_SR_ORE)) return;
    i0 = rxw;
    if ((i1 = i0 + 1) >= sizeof(bufService.rx)) i1 = 0;
    if (i1 == (i2 = rxr)) return;
    bufService.rx[i0] = c;
    rxw = i1;
    if (i0 == i2) OsFlagSet(&rxNoEmpty);
  }
}

и всех делов....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24 минуты назад, haker_fox сказал:

Но ругают на форуме почему-то только меня за то, что я ругаю куб)

Я отношусь к кубу философски: хотят мыши жрать кактус - пусть плачут и колятся, поэтому просто чаще всего молча прохожу мимо тем про куб. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

46 minutes ago, jcxz said:

и всех делов....

Кратко. А мне понравилось больше передавать через ПДП: количество байт на передачу известно. Принимаю по прерываниям. Хотя тоже можно по ПДП, но для пакетной передачи. А если принять с текстовой консоли, то, ИМХО, прерывания не обременяют.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 минут назад, haker_fox сказал:

Кратко. А мне понравилось больше передавать через ПДП: количество байт на передачу известно. Принимаю по прерываниям.

В приведённом ISR только приём. Передача сделана как раз через DMA.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 hours ago, Сергей Борщ said:

Не выставляется или вы не попадаете в последнее условие, потому что флаг сбрасывается после чтения SR и DR в первом условии? Полагаю, что все же второе. Я не знаком с кубом, но внимательно читаю документацию на контроллер и его регистры. Из этой документации становится понятно, что ваш обработчик написан неправильно:

1) Нужно один раз в начале обработчика считать регистр статуса и потом во всех условиях работать со считанным значением, а не теребить SR при проверке каждого флага, как это делают недалекие авторы куба.

2) Многие биты в этом регистре сбрасываются автоматически чтением DR после чтения SR и вызов USART_ClearITPendingBit на них никоим образом не влияет.

Читайте справочное руководство (reference manual) на контроллер, а не только названия функций в кубе.

 

Сергей спасибо за критику. Го это не HAL а SPL.

Сделано как описывают сами ST в своем референсе.

Даташит тоже читаю, и еррату тоже.

За замечание еще раз спасибо.

Буду пробовать.

И в Кале перед функциями стоит префикс HAL. Халом я тоже не пользуюсь.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 hours ago, zaicev_ekb said:

это не HAL а SPL.

Оно же вообще deprecated уже давно!

Если вам так хочется пользоваться чужими библиотеками "абстракций" и добавлять в свой код лютый оверхед, лучше попробуйте opencm3. Она по крайней мере не страдает ТАКИМ оверхедом, как SPL.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 7/7/2020 at 5:31 AM, zaicev_ekb said:

Доброго времени суток всем.

Столкнулся с непонятным явлением

USART сконфигурированный с одними параметрами связи, отвечает на запросы с другими параметрами связи

 

Здесь специалисты уже посоветовали. Я вставлю свои пять копеек.

Отлаживая UART коммуникацию, я начал сталкиваться со спорадическими потерями байтов как на STM32F10x, так и (и особенно) на STM32F0xx. В процессе отладки, когда я хотел глянуть по шагам, что там с битами в SR происходит, я вставил команду чтения SR сразу на входе в прерывание:

void STDIO_IRQHandler(void)
{
    STDIO_DEVICE->SR;           // unbelievable but reading SR before 
    bufio_IRQHandler(&FIFO);    // helps to avoid byte loss. 28.04.14.  
}

И о, чудо! - ошибки ушли навсегда!

Я не стал глубоко копать, почему так происходит, и объяснить не смогу. Работает, и работает (и весьма надежно). Чистая эмпирика и удача, я и оставил, как есть. F10x вообще, как первая Cortex серия от STM, имеет весьма глючную периферию. Например, запустить разумно I2C на нем весьма нетривиально, о чем писано-переписано на форуме, в том числе и мной.

 

Попробуйте трюк 17. Хотя проблема в TX? Может быть, немного не совпадают скорости? RC генератор (HSI) не точный, или где-то +/-1 в делителе...

Изменено пользователем KnightIgor

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 минут назад, KnightIgor сказал:

я вставил команду чтения SR сразу на входе в прерывание:

А где-ж ещё её вставлять? Вроде в начале - это как бы само собой разумеется.

Цитата

RC генератор (HSI) не точный, или где-то +/-1 в делителе...

"Не точный" - это мягко сказано. У меня на плате с али (STM32F103R8T6) частота HSI по дефолту == ~6.326 МГц.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...