Neo_Matrix 0 25 апреля, 2019 Опубликовано 25 апреля, 2019 (изменено) · Жалоба Столкнулся со странным поведение периферии UART4(на других не замечено), а точнее подвисанием. Итак имеется 2 устройства одно из них мое второе третьей стороны, оба устройства подключены по RS232. С моей стороны стоит процессор STM32F407 за ним MAX3232(питание от 3.3вольта) с сапрессорами с другой стороны находится такая же MAX3232 с сапрессорами далее уходит на проц(не смотрел какой). Так вот недалекий обслуживающий персонал частенько вынимает коннектор RS232 "на горячую", поскольку мое устройство питается от блока питания стороннего устройства земли(GND) у них в этот момент не разрываются, но конструкция разъема такова, что при попадании на металлический корпус коннектора RX, TX могут на него замкнуть(от этого защищают резисторы и сапрессоры). Теперь суть проблемы: В момент отключения кабеля посылка данных приходящих ко мне может быть принята не полностью, на что мой софт отвечает NACK(0x15), по непонятной мне причине в этот момент может выставится флаг LBD, который используется если настроить порт как LIN, но я не использую этот самый LIN и он не активен и прерываний от него нет, именно в такие моменты периферия подвисает. Если потом вернуть разъем на место, то прерывания RXNE, TXE более не срабатывают, а софт моей задачи вылетает по таймауту. В начале попробовал сбрасывать сам флаг LBD - флаг нормально сбрасывается но передача не возобновляется. Нашел 2 способа решить проблему костылем: 1) Сбросить ЮАРТ периферию и заново перенастроить. 2) При появлении флага LBD в регистре DR содержится(в случае зависания всегда) значение 0x0015(Мой ответ NACK). Если произвести запись в регистр любых данных все начинает снова работать, даже не нужно сбрасывать LBD. LBD - продолжаю сбрасывать для того что бы хоть как то отследить повторение зависания. Еще раз повторюсь функционал LIN Не используется мной, а отслеживание флага LBD сделано для работы костыля. Так же повторюсь, что прерывания после такой ситуации именно перестают срабатывать, а не ПО подвисает в прерывании. Использую следующую инициализацию порта: LL_USART_DisableRTSHWFlowCtrl(UART4); LL_USART_DisableCTSHWFlowCtrl(UART4); LL_USART_DisableLIN(UART4); LL_USART_DisableSCLKOutput(UART4); LL_USART_DisableSmartcard(UART4); LL_USART_DisableIrda(UART4); LL_USART_DisableHalfDuplex(UART4); LL_USART_SetTransferDirection(UART4, LL_USART_DIRECTION_TX_RX); LL_USART_SetParity(UART4, LL_USART_PARITY_NONE); LL_USART_SetDataWidth(UART4, LL_USART_DATAWIDTH_8B); LL_USART_SetStopBitsLength(UART4, LL_USART_STOPBITS_1); LL_USART_SetOverSampling(UART4, LL_USART_OVERSAMPLING_16); LL_USART_SetBaudRate(UART4, RCC_GetPCLK1ClockFreq(RCC_GetHCLKClockFreq(RCC_GetSystemClockFreq())), LL_USART_OVERSAMPLING_16, baudrate); LL_USART_Enable(UART4); LL_USART_EnableIT_RXNE(UART4); Может кто то сталкивался с такой ситуацией? Так как 2 вышеописанных метода решения это "костыли" чистой воды, прошу помочь проблему более правильно. Изменено 25 апреля, 2019 пользователем Neo_Matrix Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 25 апреля, 2019 Опубликовано 25 апреля, 2019 · Жалоба Просмотрел еррату, есть похожая ошибка, но она проявляет себя только при аппаратном контроле потока, который у меня выключен. В итоге непонятно. Цитата 2.7.7 Break request can prevent the Transmission Complete flag (TC) from being set Description After the end of transmission of a data (D1), the Transmission Complete (TC) flag will not be set if the following conditions are met: • CTS hardware flow control is enabled. • D1 is being transmitted.• A break transfer is requested before the end of D1 transfer.• nCTS is de-asserted before the end of D1 data transfer. Workaround If the application needs to detect the end of a data transfer, the break request should be issued after checking that the TC flag is set. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ivan24190 0 25 апреля, 2019 Опубликовано 25 апреля, 2019 · Жалоба 3 hours ago, Neo_Matrix said: Столкнулся со странным поведение периферии UART4(на других не замечено), а точнее подвисанием. Итак имеется 2 устройства одно из них мое второе третьей стороны, оба устройства подключены по RS232. С моей стороны стоит процессор STM32F407 за ним MAX3232(питание от 3.3вольта) с сапрессорами с другой стороны находится такая же MAX3232 с сапрессорами далее уходит на проц(не смотрел какой). Так вот недалекий обслуживающий персонал частенько вынимает коннектор RS232 "на горячую", поскольку мое устройство питается от блока питания стороннего устройства земли(GND) у них в этот момент не разрываются, но конструкция разъема такова, что при попадании на металлический корпус коннектора RX, TX могут на него замкнуть(от этого защищают резисторы и сапрессоры). Теперь суть проблемы: В момент отключения кабеля посылка данных приходящих ко мне может быть принята не полностью, на что мой софт отвечает NACK(0x15), по непонятной мне причине в этот момент может выставится флаг LBD, который используется если настроить порт как LIN, но я не использую этот самый LIN и он не активен и прерываний от него нет, именно в такие моменты периферия подвисает. Если потом вернуть разъем на место, то прерывания RXNE, TXE более не срабатывают, а софт моей задачи вылетает по таймауту. В начале попробовал сбрасывать сам флаг LBD - флаг нормально сбрасывается но передача не возобновляется. Нашел 2 способа решить проблему костылем: 1) Сбросить ЮАРТ периферию и заново перенастроить. 2) При появлении флага LBD в регистре DR содержится(в случае зависания всегда) значение 0x0015(Мой ответ NACK). Если произвести запись в регистр любых данных все начинает снова работать, даже не нужно сбрасывать LBD. LBD - продолжаю сбрасывать для того что бы хоть как то отследить повторение зависания. Еще раз повторюсь функционал LIN Не используется мной, а отслеживание флага LBD сделано для работы костыля. Так же повторюсь, что прерывания после такой ситуации именно перестают срабатывать, а не ПО подвисает в прерывании. Использую следующую инициализацию порта: LL_USART_DisableRTSHWFlowCtrl(UART4); LL_USART_DisableCTSHWFlowCtrl(UART4); LL_USART_DisableLIN(UART4); LL_USART_DisableSCLKOutput(UART4); LL_USART_DisableSmartcard(UART4); LL_USART_DisableIrda(UART4); LL_USART_DisableHalfDuplex(UART4); LL_USART_SetTransferDirection(UART4, LL_USART_DIRECTION_TX_RX); LL_USART_SetParity(UART4, LL_USART_PARITY_NONE); LL_USART_SetDataWidth(UART4, LL_USART_DATAWIDTH_8B); LL_USART_SetStopBitsLength(UART4, LL_USART_STOPBITS_1); LL_USART_SetOverSampling(UART4, LL_USART_OVERSAMPLING_16); LL_USART_SetBaudRate(UART4, RCC_GetPCLK1ClockFreq(RCC_GetHCLKClockFreq(RCC_GetSystemClockFreq())), LL_USART_OVERSAMPLING_16, baudrate); LL_USART_Enable(UART4); LL_USART_EnableIT_RXNE(UART4); Может кто то сталкивался с такой ситуацией? Так как 2 вышеописанных метода решения это "костыли" чистой воды, прошу помочь проблему более правильно. А может стоит проверять флаги ошибок приема (FE, NF и т.д.) и сбрасывать их? Т.к. в некоторых случаях прием может "затыкаться" если эти флаги установлены. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 25 апреля, 2019 Опубликовано 25 апреля, 2019 (изменено) · Жалоба 25 минут назад, ivan24190 сказал: А может стоит проверять флаги ошибок приема (FE, NF и т.д.) и сбрасывать их? Т.к. в некоторых случаях прием может "затыкаться" если эти флаги установлены. ORE - проверяю, на остальные прерывания отключены. В дебагере четко видно, что ни один из флагов(FE и т.д.) в момент зависания приема - не выставлен, кроме того, как объяснить продолжение нормальной работы после записи в регистр DR(чтение этого регистра проблему не убирает!) Изменено 25 апреля, 2019 пользователем Neo_Matrix Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 26 апреля, 2019 Опубликовано 26 апреля, 2019 · Жалоба Добавил проверку ошибок UART по принципу проверили флаг -> напечатали принтом ошибку -> сбросили флаг. Несколько раз при горячем отключении ошибки проскакивали, но UART от их обработки виснуть не перестал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vlad_new 1 28 апреля, 2019 Опубликовано 28 апреля, 2019 · Жалоба Ну во первых флаг LBD - это не обязательно LIN. Например я его использую как флаг начала пакета. Во вторых странно, что у вас не выставляется флаг FE. Хотя он не на что и не влияет. В третьих флаг OVR заслуживает отдельного внимания, поскольку ( как я понял в некоторых камнях ) он блокирует дальнейший приём. В мэнуале как то странно написано, что сбросить его можно чтением приемника ??? и/или ??? чтением регистра SR (вроде). Поэтому при приёме байта сначала вычитываем RX и SR в каие нибудь переменные, а потом уже занимаемся всем остальным. Правда во время обработки приема байта, флаг OVR опять может установиться ( от разного там дребезга в контактах ). Ситуация редкая, но я уже с этим сталкивался (приёмник просто намертво виснет, хотя казалось бы, что ранее флаг OVR был сброшен). Вообщем написав уже с не один десяток разных обработчиков пакетов, везде вылезало что то своё и до всего приходилось докапываться самому. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dsl2640free 0 28 апреля, 2019 Опубликовано 28 апреля, 2019 · Жалоба У меня так тоже было. помогла специальная инициализация: GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); //UART4_TX PC.10 PC.11 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4); GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4); //Usart1 NVIC NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_InitStructure.USART_BaudRate = Baud; USART_InitStructure.USART_WordLength = USART_WordLength_8b; 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(UART4, &USART_InitStructure); USART_ITConfig(UART4, USART_IT_RXNE, ENABLE); USART_Cmd(UART4, ENABLE); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 28 апреля, 2019 Опубликовано 28 апреля, 2019 · Жалоба И что в ней специального? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 9 мая, 2019 Опубликовано 9 мая, 2019 (изменено) · Жалоба Уезжал на праздники, потому долго не отвечал. В 28.04.2019 в 11:19, vlad_new сказал: Ну во первых флаг LBD - это не обязательно LIN. Например я его использую как флаг начала пакета. Во вторых странно, что у вас не выставляется флаг FE. Хотя он не на что и не влияет. В третьих флаг OVR заслуживает отдельного внимания, поскольку ( как я понял в некоторых камнях ) он блокирует дальнейший приём. В мэнуале как то странно написано, что сбросить его можно чтением приемника ??? и/или ??? чтением регистра SR (вроде). Поэтому при приёме байта сначала вычитываем RX и SR в каие нибудь переменные, а потом уже занимаемся всем остальным. Правда во время обработки приема байта, флаг OVR опять может установиться ( от разного там дребезга в контактах ). Ситуация редкая, но я уже с этим сталкивался (приёмник просто намертво виснет, хотя казалось бы, что ранее флаг OVR был сброшен). Вообщем написав уже с не один десяток разных обработчиков пакетов, везде вылезало что то своё и до всего приходилось докапываться самому. Ну, LBD у меня при нормальном приеме данных не выставляется(если кабель не дергать на горячую), или я не замечал. FE точно не выставляется, прикрепил скриншот к сообщению, там написано, что этот флаг работает только в мультибуферном режиме . А что за флаг OVR, не нашел такого? Спойлер В 28.04.2019 в 12:19, dsl2640free сказал: У меня так тоже было. помогла специальная инициализация: Не смог найти нечего специального, ткните носом плиз. Изменено 9 мая, 2019 пользователем Neo_Matrix Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Картошка 0 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба Код программы прерывания по приему можно увидеть ? Можно не весь - хотя-бы половину, но с самого начала. Для примера: распространенные примеры процедур приема по CUBE HALL - требует мусорника и вечного забытия, а не использования. (HALL STM (индус-софт) разработанное API не позволяет правильно обрабатывать ошибки, так как сброс некоторых ошибок происходит после прочтения регистра SR, а предоставленый халом API может за 1 раз проверить только один указаный бит - в общем архичёсы были еще те). Его писали студенты индусы не читающие тех. мануалы - да и еще в аквариумных условиях в офисе, без помех. И этот код никак не фиксится - примеров с чудо обработкой данных - полно и там одна и та же ошибка. Благо дело аппаратные нюансы по сбросам ошибок на другой периферии более менее нормальные, в противном случае горе индусы бы и дальше слонов пасли. Софтварный (не DMA) прием любого байта должен начинаться в 100 % случаев с двух действий - чтение SR а потом чтение DR, никак не иначе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба 47 минут назад, Картошка сказал: Софтварный (не DMA) прием любого байта должен начинаться в 100 % случаев с двух действий - чтение SR а потом чтение DR, никак не иначе. +1, с таким подходом ни разу в жизни не ловил подвисание UART. uint32_t sr = USART1->SR; if(sr & USART_SR_RXNE) { if(sr & (USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE)) { //Была ошибка в приеме байта USART1->DR; } else { uint8_t RCV_data = USART1->DR; // и делай с ним что хошь } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 14 мая, 2019 Опубликовано 14 мая, 2019 (изменено) · Жалоба DMA не использую, так как скорость 9600, максимальная посылка байтов 100 от силы, в основном по 5-10 байт, периодичность посылок 100мс а то и более. Как видите в ДМА нет резона. Вот обработчик прерывания, правда не последней версии. Но глючит в любом из них.(Немного отредактировал пост) void uart_irq_handler(uint32_t uart_number) { uart_data_t *uart_data; volatile uint32_t tmp_reg; uint32_t cr3_reg; uint32_t cr1_reg; uint32_t sr_reg; uint8_t tmp_error = CLEAR; union { uint8_t data_8[2]; uint16_t data_16; } tmp_data = {0}; union { uint8_t *pdata_8; uint16_t *pdata_16; void *data_void; } tmp_pdata; uart_data = get_uart_port_data(uart_number); cr3_reg = read_reg(uart_data->uart_typedef, CR3); cr1_reg = read_reg(uart_data->uart_typedef, CR1); sr_reg = read_reg(uart_data->uart_typedef, SR); if((read_bit(cr1_reg, LL_USART_CR1_PEIE) != (CLEAR)) && \ (read_bit(sr_reg, LL_USART_SR_PE) != (CLEAR))) { tmp_error |= UART_ERROR_PE; } if(read_bit(cr3_reg, LL_USART_CR3_EIE) != (CLEAR)) { if(read_bit(sr_reg, USART_SR_ORE) != (CLEAR)) { tmp_error |= UART_ERROR_ORE; } if(read_bit(sr_reg, LL_USART_SR_FE) != (CLEAR)) { tmp_error |= UART_ERROR_FE; } if(read_bit(sr_reg, LL_USART_SR_NE) != (CLEAR)) { tmp_error |= UART_ERROR_NE; } } if((read_bit(cr1_reg, USART_CR1_RXNEIE) != (CLEAR))) { if(read_bit(sr_reg, USART_SR_ORE) != (CLEAR)) { tmp_error |= UART_ERROR_ORE; } if(read_bit(sr_reg, USART_SR_RXNE) != (CLEAR)) { if(read_bit(cr1_reg, USART_CR1_M) != (CLEAR)) { tmp_data.data_16 = (uint16_t)(read_bit_reg(uart_data->uart_typedef, DR, USART_DR_DR)); tmp_pdata.data_void = (void *)&tmp_data.data_16; } else { tmp_data.data_8[1] = (uint8_t)(read_bit_reg(uart_data->uart_typedef, DR, USART_DR_DR)); tmp_pdata.data_void = (void *)&tmp_data.data_8; } drv_rx_from_isr(uart_data->driver_data, tmp_pdata.data_void); } } if(tmp_error != CLEAR) { tmp_reg = read_reg(uart_data->uart_typedef, SR); (void)tmp_reg; tmp_reg = read_reg(uart_data->uart_typedef, DR); (void)tmp_reg; //tmp_data.data_8[0] |= tmp_error; drv_err_from_isr(uart_data->driver_data, tmp_error); } if((read_bit(cr1_reg, USART_CR1_TXEIE) != (CLEAR)) && \ (read_bit(sr_reg, USART_SR_TXE) != (CLEAR))) { tmp_pdata.data_void = uart_data->uart_tx_data; if(read_bit(cr1_reg, USART_CR1_M) != (CLEAR)) { write_reg(uart_data->uart_typedef, DR, (*tmp_pdata.pdata_16 & 0x01FFU)); if(--uart_data->uart_tx_data_len == 0U) { clear_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TXEIE); set_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TCIE); } else { tmp_pdata.pdata_16++; uart_data->uart_tx_data = tmp_pdata.data_void; } } else { write_reg(uart_data->uart_typedef, DR, (*tmp_pdata.pdata_8 & 0xFFU)); if(--uart_data->uart_tx_data_len == 0U) { clear_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TXEIE); set_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TCIE); } else { tmp_pdata.pdata_8++; uart_data->uart_tx_data = tmp_pdata.data_void; } } //return; } if((read_bit(cr1_reg, LL_USART_CR1_TCIE) != (CLEAR)) && \ (read_bit(sr_reg, LL_USART_SR_TC) != (CLEAR))) { clear_bit_reg(uart_data->uart_typedef, SR, USART_SR_TC); clear_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TCIE); drv_tx_from_isr(uart_data->driver_data); //return; } } Изменено 14 мая, 2019 пользователем Neo_Matrix Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба Меня тоже бы взглючило от такого... Как писал Картошка, первым делом надо считать SR и по его содержимому уже решать что делать. Читать DR только если взведён RXNE, а использовать как валидный только при отсутствии битов ошибки в SR. Лучше SR и DR один раз считать во временные локальные переменные, они будут в регистрах процессора и оптимизатор с ними справится. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба Ну и где же регистр SR читается не первым? Имеете ввиду CR1, CR3. Как же без их чтения узнать включено ли прерывание в данный момент по определенному событию? Кроме того DR там и читается только при условии, что RXNE установлен при включенном соответствующем прерывании, в других случаях он читается только для очистки флагов ошибок и об этом явным образом написано в даташите. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба Когда я писал ответ там был совсем другой код. И всё равно, зачем обрабатывать ошибки, если не взведён RXNE? А что вот это за конструкция, кстати? Дичь какая-то. volatile uint32_t tmp_reg; tmp_reg = read_reg(uart_data->uart_typedef, DR); (void)tmp_reg; Можно ассемблерный листинг этого куска посмотреть? Вообще, это пишется вот так. pUSART->DR; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться