firstvald 22 6 марта, 2016 Опубликовано 6 марта, 2016 (изменено) · Жалоба Кристалл stm32f100. Плата Discovery. Вижу, что передача по USART начинается с задержкой. Т е после записи в DR, на ножке процессора посылка появляется примерно через время равное передачи байта (без стопов и паритета) на выбранной скорости. Для 115200 физически передача начинается через 8 микросекунд, для 19200 - через 400, для 1200 - через 10 миллисекунд. Т е такое впечатление, что после записи в DR автомат вхолостую отрабатывает сдвиг регистра ничего не выдавая на ножку и после одного холостого цикла уже забирает данные из DR. При одновременной работе нескольких портов теряется первый или второй байт в передаваемой последовательности или даже первый со вторым переставляются местами (во всех портах или в каком то одном , картина может меняться при изменении кода). Причем, даже в длинной последовательности все остальные байты передаются нормально. Это возникает при как при одновременной работе нескольких портов так и если оставить один порт. Инициирование USART //Инициируем UARTы void USART1_INI(unsigned char spd, unsigned char par, unsigned char stp) //spd - скорости обмена // 10 115200 // 9 57600 // 8 38400 // 7 19200 // 6 9600 // 5 4800 // 4 2400 // 3 1200 // 2 600 //par - паритет // 0 без паритета // 1 нечетный паритет // 2 четный паритет //stp - число стоп битов // 0, 1 - 1 // 2 - 2 // // // { GPIO_InitTypeDef GPIO_InitStructure; short unsigned int i; //********************************************************* //Конфигурируем ножки под ввод вывод //включаем тактирование портов RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;//GPIOA //TX1 PA9 //Ножка назначается на вывод пуш пуль GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA , &GPIO_InitStructure); //RX1 PA10 //Ножка назначается на ввод GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA , &GPIO_InitStructure); USART1->CR1=0; USART1->CR1|=USART_CR1_UE;//включили UART USART1->CR1&=~USART_CR1_M;//8 бит USART1->CR1&=~USART_CR1_WAKE;// пробуждение по IDLE LINE //if(par==0){ USART1->CR1&=~USART_CR1_PCE;//без паритета USART1->CR1&=~USART_CR1_PS;// нечетный паритет USART1->CR1&=~USART_CR1_M;//8 бит // } if(par==1){ USART1->CR1|=USART_CR1_PCE;//паритет USART1->CR1|=USART_CR1_PS;// нечетный паритет USART1->CR1|=USART_CR1_M;//9 бит } if(par==2){ USART1->CR1|=USART_CR1_PCE;//паритет USART1->CR1&=~USART_CR1_PS;// четный паритет USART1->CR1|=USART_CR1_M;//9 бит } USART1->CR1|=USART_CR1_PEIE;//общее разрешение прерывания // USART1->CR1|=USART_CR1_TXEIE;//разрешение прерывания по опустошению буфера передачи USART1->CR1&=~USART_CR1_TXEIE;//запрещение прерывания по опустошению буфера передачи USART1->CR1&=~USART_CR1_TCIE;//запрещено прерывание от "передача закончена" //USART1->CR1|=USART_CR1_TCIE;// прерывание от "передача закончена" USART1->CR1|=USART_CR1_RXNEIE;// разрешение прерывания по приему USART1->CR1&=~USART_CR1_IDLEIE;//запрещено прерывание от IDLE USART1->CR1|=USART_CR1_TE;//передатчик включен USART1->CR1|=USART_CR1_RE;//приемник включен USART1->CR1&=~USART_CR1_RWU;//приемник в активном режиме USART1->CR1&=~USART_CR1_SBK;//запрос передачи длинного 0 выключен USART1->CR2=0; //if(stp<=1){//1 стоп USART1->CR2&=~USART_CR2_STOP;//1 стоп // } if(stp==2){//2 стоп USART1->CR2&=~USART_CR2_STOP;//1 стоп USART1->CR2|=USART_CR2_STOP_1;//2 стоп } USART1->CR3=0; USART1->SR&=0;//Флаги всех прерываний сбросили USART1->BRR=0X0480;//19200 if(spd==10){ USART1->BRR=0X00C0;//115200 } // готовим буферы обмена //#define rx_buf_long 256 //#define tx_buf_long 256 i=0; while(i<rx_buf_long){ rx_buf1[i]=0; i++; } i=0; while(i<tx_buf_long){ tx_buf1[i]=0; i++; } USART1->SR=0;//СБРАСЫВАЕМ ФЛАГИ // CTS // LBD // TC // RXNE // IDLE // NE // rx_ptr1=0; tx_ptr1=0; //индекс последнего передаваемого элемента буфера tx_last1=0; rx_state1=0; tx_state1=0; } Само прерывание от одного порта void USART1_IRQHandler(void) { //прием if((USART1->SR&USART_SR_RXNE)!=0) {//что то пришло USART1->SR&=~USART_SR_RXNE;//сбросим флаг rx_buf1[rx_ptr1]=USART1->DR; if(rx_ptr1<rx_buf_long){ rx_ptr1++; } }//что то пришло //передача if((USART1->SR&USART_SR_TC)!=0) {//данные переписались из буфера в сдвиговый регистр и ушли из него if(tx_state1==1){//идет передача USART1->SR&=~USART_SR_TC;//сбросим флаг if(tx_ptr1>=tx_last1){//ушел последний байт tx_state1=0; GPIOC->ODR &= ~GPIO_ODR_ODR4;// смотрим этой ножкой момент, когда закончилась передача USART1->CR1&=~USART_CR1_TCIE ; }//ушел последний байт else{//передаем дальше tx_ptr1++; USART1->DR=tx_buf1[tx_ptr1]; }//передаем дальше }//идет передача else{//фантомное прерывание- мы ничего не должны передавать USART1->CR1&=~USART_CR1_TCIE ;//сбросим разрешение этого прерывания }//фантомное прерывание- мы ничего не должны передавать }//данные переписались из буфера в сдвиговый регистр USART1->SR=0; } и затравка которая начинает передачу: InitGPIO(); Init_OSC_my();//инициализация и переключение синхронизации USART1_INI(3,2,2);//1200 tx_buf1[0]=0x30; tx_buf1[1]=0x31; tx_buf1[2]=0x32; tx_buf1[3]=0x33; tx_buf1[4]=0x34; tx_buf1[5]=0x35; tx_buf1[6]=0x36; tx_buf1[7]=0x37; tx_buf1[8]=0x38; tx_buf1[9]=0x39; tx_buf1[10]=0x41; tx_buf1[11]=0x42; tx_buf1[12]=0x43; tx_buf1[13]=0x44; tx_buf1[14]=0x45; tx_buf1[15]=0x46; tx_buf1[16]=0x47; tx_buf1[17]=0x48; tx_buf1[18]=0x49; tx_buf1[19]=0x4a; tx_buf1[20]=0x4b; tx_state1=1; tx_last1=20; tx_ptr1=0; __NOP(); USART1->CR1|=USART_CR1_TCIE ; GPIOC->ODR |= GPIO_ODR_ODR4;// между выставлением этой ножки и началом передачи на ножке - выдержка времени USART1->DR=tx_buf1[tx_ptr1]; Изменено 6 марта, 2016 пользователем IgorKossak [codebox] для длинного кода, [code] - для короткого!!! форматирование Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlanDrakes 1 6 марта, 2016 Опубликовано 6 марта, 2016 (изменено) · Жалоба На кристалле STM32F107 работает следующий код: uint8_t UART4_TX_BUFFER[uART_TX_BUFFER_SIZE]; // Буфер передачи UART' volatile uint16_t UART4_TX_POS, UART4_WR_POS; // Указатели буфера. void DMA2_Channel5_IRQHandler(void) { if (DMA2->ISR & DMA_ISR_TCIF5) { DMA2->IFCR = DMA_IFCR_CTCIF5; // Сбрасываем бит прерывания. DMA_STATE &= ~DMA_STATE_UART_ACTIVE; UART4_ActivateDMA(); }; }; void init_DMA_uart(void) { RCC->AHBENR |= RCC_AHBENR_DMA2EN; UART4->CR3 |= USART_CR3_DMAT; UART4->SR &= ~USART_SR_TC; DMA2_Channel5->CCR = 0; DMA2_Channel5->CPAR = (uint32_t)&(UART4->DR); NVIC_EnableIRQ(DMA2_Channel5_IRQn); NVIC_SetPriority(DMA2_Channel5_IRQn, 0x04); }; void init_uart(void) { SystemCoreClockUpdate(); // Обновляем рабочую частоту. RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // Включаем тактирование порта с UART GPIOC->ODR |= 0x00000C00; // Поднимаем пины. GPIOC->CRH |= 0x0000FF00; // GPIOC[10:11] -> 50MHz, OpenDrain Alternate. RCC->APB1ENR |= RCC_APB1ENR_UART4EN; // Включаем UART4 UART4->CR2 = 0; // Настройки. Сбрасываем. UART4->CR3 = 0; // Продолжаем. if (RCC->CFGR & RCC_CFGR_PPRE1_DIV2) { UART4->BRR = (SystemCoreClock / 115200 / 2); // Ибо делим на 2 } else { UART4->BRR = (SystemCoreClock / 115200); // Или не делим. }; UART4->CR1 = (USART_CR1_TE | USART_CR1_RE | USART_CR1_UE); // Разрешаем работу UART. init_DMA_uart(); }; void UART4_ActivateDMA(void) { uint16_t CURR_WR_POS = UART4_WR_POS; if (!(DMA_STATE & DMA_STATE_UART_ACTIVE)) { DMA2_Channel5->CCR &= ~DMA_CCR_EN; if (UART4_TX_POS == CURR_WR_POS) { // Собственно, позиции начала и конца совпали. } else { // Есть разница между позициями буфера. Значит, нужно передавать данные. // Начальная точка передачи - текущее значение указателя TX. DMA2_Channel5->CMAR = (uint32_t)&(UART4_TX_BUFFER[(UART4_TX_POS)]); // Указатель на память if (UART4_TX_POS < CURR_WR_POS) { // Линия DMA2_Channel5->CNDTR = (CURR_WR_POS - UART4_TX_POS); // Как раз нужная разница. UART4_TX_POS = CURR_WR_POS; } else { // Кольцо DMA2_Channel5->CNDTR = (UART_TX_BUFFER_SIZE - UART4_TX_POS); UART4_TX_POS = 0; }; DMA_STATE |= DMA_STATE_UART_ACTIVE; DMA2_Channel5->CCR = (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE | DMA_CCR_EN); }; }; }; void console_put(char *text) { // Можно попытаться написать под реализацию на двух каналах DMA... Тогда будет ещё быстрее. while(*text) { // Пока не нуль-терминатор UART4_TX_BUFFER[uART4_WR_POS] = *text; // Копируем данные в буфер text++; // Сдвигаем указатель текста. UART4_WR_POS++; // Сдвигаем указатель на 1 байт дальше. UART4_WR_POS = UART4_WR_POS & UART_TX_MASK; // Указатель должен быть в пределах допустимых значений. }; // Здесь всё хорошо, записываем от старой позиции до новой. UART4_ActivateDMA(); }; Используется DMA и буфер передачи (32/64/128 и более байт). Данные не теряются при передаче. Изменено 6 марта, 2016 пользователем IgorKossak [codebox] для длинного кода, [code] - для короткого!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
firstvald 22 6 марта, 2016 Опубликовано 6 марта, 2016 · Жалоба спасибо огромное! это очень пригодится ! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlanDrakes 1 6 марта, 2016 Опубликовано 6 марта, 2016 · Жалоба Да не за что. Хотя, я просмотрел ваш код и тоже не нашёл никаких грубых ошибок. По идее, должны уходить нормально. И учтите, я использую заголовочники от HAL, но сам стараюсь писать больше на регистрах. А строки - нуль-терминированые. Пример uint8_t TXT_VAL = "Hello"; 'H','e','l','l','o',/0 Ноль после последнего байта обязателен. Ну это так, на всякий случай. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
firstvald 22 6 марта, 2016 Опубликовано 6 марта, 2016 (изменено) · Жалоба ну это важно если мы каким то подпиленным sprintf работаем. так я указываю индекс последнего символа в массиве который должен уйти на передачу. да я бы и не заметил подвоха если бы не стал внимательно смотреть что уходит и тестить в условиях одновременной работы трех портов. раньше уже отмечали, что при интенсивном обслуживании прерываний были непонятки в работе тела прерывания. высказывалось предположение что процессор попадает в код тела прерывания до того как выставятся флаги. это из за ускорения обработки одновременно возникших прерываний. и воде бы помогала задержка в начале тела прерывания. буквально несколько строк пустого или не связанного с флагами кода. я пробовал набивать начало тела нопами - не, не помогает. Изменено 6 марта, 2016 пользователем IgorKossak бездумное цитирование Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlanDrakes 1 6 марта, 2016 Опубликовано 6 марта, 2016 · Жалоба А нуль-терминированая строка может оказаться удобнее. Для функции передачи нужен только один параметр в стэке - позиция начала строки. Всё, что до нулевого символа будет скопировано в буфер отправки и передано. Кстати, в моём коде - только отправка. Приём не требовался, потому под него ничего не писалось. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
firstvald 22 6 марта, 2016 Опубликовано 6 марта, 2016 (изменено) · Жалоба это если передаем символы. последний раз у меня это было году так в 99. а дальше модбас RTU. там в пределах строки все что угодно может быть. Изменено 6 марта, 2016 пользователем IgorKossak бездумное цитирование Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 6 марта, 2016 Опубликовано 6 марта, 2016 (изменено) · Жалоба О, сколько раз уже можно просить читать документацию.... //прием if((USART1->SR&USART_SR_RXNE)!=0) {//что то пришло USART1->SR&=~USART_SR_RXNE;//сбросим флаг rx_buf1[rx_ptr1]=USART1->DR; Бит RXNE It is cleared by a read to the USART_DR register Сбрасывая его "вручную", рискуете сбросить лишнее. Кроме того, сбрасывать надо так: USART1->SR = ~ USART_SR_TC; А не так, как у Вас: USART1->SR&=~USART_SR_TC; Разницу увидите сами (представьте себе, что флаг приёма символа появился после чтения SR, но перед обратной записью в этой строке). На приёме тем более - гасятся прерывания от передатчика таким образом. Изменено 6 марта, 2016 пользователем Genadi Zawidowski Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorKossak 0 6 марта, 2016 Опубликовано 6 марта, 2016 · Жалоба firstvald, при ответе на крайнее сообщение нет нужды в цитировании. Это только загромождает форум. Модератор Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
firstvald 22 6 марта, 2016 Опубликовано 6 марта, 2016 (изменено) · Жалоба бит в регистре во все времена сбрасывался именно так: регистр &=~ (слово размером с регистр с единичным выставленным битом); хотя действительно предлагаемая функция USART_ClearFlag (из STM32F10X_USART.C)для сброса использует конструкцию USARTx->SR = (uint16_t)~USART_FLAG; но это скорее исключение(довольно безграмотное), которое вероятно работает благодаря особенностям регистра SR. При поочередной передаче флаг приема не может появится после попадания в тело прерывания, иначе как бы мы туда попали? и что вообще бы вызвало прерывание? это могло бы быть теоретически в случает одновременной передачи и приема, но обычный обмен с приборами такого не предполагает, идет запрос ответная работа. и при запросно -ответной работе появление прерывания от приема в момент передачи считается мусором и такие символы должны игнорироваться. аналогично появление прерывания от передачи в момент приема является мусором и его нужно игнорировать и выключить если оно по каким то причинам включилось. на практике при передаче в приемник действительно может попадать мусор и в некоторых вариантах обмена передаваемая строка. во всех случаях эти символы должны игнорироваться. посмотрел конструкцию USART3->SR=~USART_SR_RXNE;//**сбросим флаг тоже работает. но рекомендовать использовать это я бы никому не стал Изменено 6 марта, 2016 пользователем IgorKossak избыточное цитирование Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 6 марта, 2016 Опубликовано 6 марта, 2016 (изменено) · Жалоба При поочередной передаче флаг приема не может появится после попадания в тело прерывания, иначе как бы мы туда попали Попали по поводу прерывания от примника, а сбросили флаг передатчика. Как он появился там? Да потому, что передатчик передваал-передавал себе символ, да и передал. Если не хотите, можете продолжать... и считать допустимой работу "иногда". Как бит в переменно сбрасывается это одно, а как сбросить запрос прерывания в регистре с особенным поведением, это другое. Ситуацию со сбросом лишнего я Вам нарисовал. Изменено 6 марта, 2016 пользователем Genadi Zawidowski Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
firstvald 22 6 марта, 2016 Опубликовано 6 марта, 2016 · Жалоба да нет. по флагу от передатчика сбрасывается флаг передатчика и по флагу приемника сбрасывается флаг приемника. а если кто остался несброшеным - сбросится перед выходом из прерывания. я нигде не встречал указания, чтобы для сброса битов регистра SR требовался особый синтаксис, нигде больше не применяемый. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 6 марта, 2016 Опубликовано 6 марта, 2016 (изменено) · Жалоба При наличии других флагов прерывания (если они появились после чтения SR перед записью в него) они тоже сбросятся. Вы напишите на бумажке псевдокод того, как это произойдет. Изменено 6 марта, 2016 пользователем Genadi Zawidowski Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
firstvald 22 6 марта, 2016 Опубликовано 6 марта, 2016 · Жалоба да сбросятся, но они мне тут не нужны . не в приеме дело - ту эффект вот какой: я вижу вот что. пробую передать строку из 3 символов (0x30 0x31 0x32 ). что происходит: по записи (я все поотключал - таймеры и уарты- оставил только этот уарт) я сейчас с 3 работаю - там код одинаковый USART3->DR=tx_buf3[tx_ptr3]; на ножку вовсе ничего не передается, но возникает прерывание с выставлением TC . у меня в прерывании честно указатель буфера инкрементируется и в регистр DR записывается следующий байт т е 1. и вот он появляется на ножке. а после выхода из прерывания на передачу отправляется 0 байт из буфера! т е в линии оказывается что нулевой и первый байты оказываются переставленными местами! а вот начиная со следующего прерывания последовательность передачи - правильная. и я вижу что уходит 0x31 0x30 0x32 вот что происходит в начале - почему переставляется 0 и первый байт местами я понять не могу. и спасибо огромное за внимание! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 6 марта, 2016 Опубликовано 6 марта, 2016 · Жалоба acc = SR 0x01 interrupt! SR=0x03 - появился дополнительный бит acc = acc & 0xfe = 0x01 & 0xfe = 0x00 SR = 0x00 - сбрасывабтся все биты вообще Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться