реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> stm32f100 USART задержка передачи и потеря символов, Физически передача начинается с задержкой. Теряется 1 или 2 байт.
firstvald
сообщение Mar 6 2016, 12:58
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



Кристалл stm32f100. Плата Discovery.

Вижу, что передача по USART начинается с задержкой. Т е после записи в DR, на ножке процессора посылка появляется примерно через время равное передачи байта (без стопов и паритета) на выбранной скорости. Для 115200 физически передача начинается через 8 микросекунд, для 19200 - через 400, для 1200 - через 10 миллисекунд. Т е такое впечатление, что после записи в DR автомат вхолостую отрабатывает сдвиг регистра ничего не выдавая на ножку и после одного холостого цикла уже забирает данные из DR.

При одновременной работе нескольких портов теряется первый или второй байт в передаваемой последовательности или даже первый со вторым переставляются местами (во всех портах или в каком то одном , картина может меняться при изменении кода). Причем, даже в длинной последовательности все остальные байты передаются нормально. Это возникает при как при одновременной работе нескольких портов так и если оставить один порт.


Инициирование USART

CODE
//Инициируем 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;

}


Само прерывание от одного порта

CODE
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;

}



и затравка которая начинает передачу:

CODE
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];


Сообщение отредактировал IgorKossak - Mar 6 2016, 14:00
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!! форматирование
Go to the top of the page
 
+Quote Post
AlanDrakes
сообщение Mar 6 2016, 14:43
Сообщение #2


Частый гость
**

Группа: Участник
Сообщений: 101
Регистрация: 2-05-15
Из: Россия, Омск
Пользователь №: 86 474



На кристалле STM32F107 работает следующий код:
CODE
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 и более байт).
Данные не теряются при передаче.

Сообщение отредактировал IgorKossak - Mar 6 2016, 15:46
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 6 2016, 16:22
Сообщение #3


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041






спасибо огромное!

это очень пригодится !
Go to the top of the page
 
+Quote Post
AlanDrakes
сообщение Mar 6 2016, 16:37
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 101
Регистрация: 2-05-15
Из: Россия, Омск
Пользователь №: 86 474



Да не за что.
Хотя, я просмотрел ваш код и тоже не нашёл никаких грубых ошибок. По идее, должны уходить нормально.
И учтите, я использую заголовочники от HAL, но сам стараюсь писать больше на регистрах.
А строки - нуль-терминированые.
Пример
uint8_t TXT_VAL = "Hello";
'H','e','l','l','o',/0
Ноль после последнего байта обязателен. Ну это так, на всякий случай.
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 6 2016, 16:44
Сообщение #5


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



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

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

Сообщение отредактировал IgorKossak - Mar 6 2016, 19:54
Причина редактирования: бездумное цитирование
Go to the top of the page
 
+Quote Post
AlanDrakes
сообщение Mar 6 2016, 16:46
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 101
Регистрация: 2-05-15
Из: Россия, Омск
Пользователь №: 86 474



А нуль-терминированая строка может оказаться удобнее. Для функции передачи нужен только один параметр в стэке - позиция начала строки. Всё, что до нулевого символа будет скопировано в буфер отправки и передано.
Кстати, в моём коде - только отправка. Приём не требовался, потому под него ничего не писалось.
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 6 2016, 16:49
Сообщение #7


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



это если передаем символы. последний раз у меня это было году так в 99. а дальше модбас RTU. там в пределах строки все что угодно может быть.

Сообщение отредактировал IgorKossak - Mar 6 2016, 19:55
Причина редактирования: бездумное цитирование
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Mar 6 2016, 18:57
Сообщение #8


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



О, сколько раз уже можно просить читать документацию....

Код
//прием
    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, но перед обратной записью в этой строке).
На приёме тем более - гасятся прерывания от передатчика таким образом.

Сообщение отредактировал Genadi Zawidowski - Mar 6 2016, 18:58
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Mar 6 2016, 19:56
Сообщение #9


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



firstvald, при ответе на крайнее сообщение нет нужды в цитировании. Это только загромождает форум.
Модератор
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 6 2016, 20:45
Сообщение #10


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



Цитата(Genadi Zawidowski @ Mar 6 2016, 22:57) *


бит в регистре во все времена сбрасывался именно так:
регистр &=~ (слово размером с регистр с единичным выставленным битом);

хотя действительно предлагаемая функция USART_ClearFlag (из STM32F10X_USART.C)для сброса использует конструкцию
USARTx->SR = (uint16_t)~USART_FLAG; но это скорее исключение(довольно безграмотное), которое вероятно работает благодаря особенностям регистра SR.



При поочередной передаче флаг приема не может появится после попадания в тело прерывания, иначе как бы мы туда попали? и что вообще бы вызвало прерывание? это могло бы быть теоретически в случает одновременной передачи и приема, но обычный обмен с приборами такого не предполагает, идет запрос ответная работа. и при запросно -ответной работе появление прерывания от приема в момент передачи считается мусором и такие символы должны игнорироваться. аналогично появление прерывания от передачи в момент приема является мусором и его нужно игнорировать и выключить если оно по каким то причинам включилось.

на практике при передаче в приемник действительно может попадать мусор и в некоторых вариантах обмена передаваемая строка. во всех случаях эти символы должны игнорироваться.

посмотрел конструкцию

USART3->SR=~USART_SR_RXNE;//**сбросим флаг

тоже работает. но рекомендовать использовать это я бы никому не стал

Сообщение отредактировал IgorKossak - Mar 6 2016, 21:17
Причина редактирования: избыточное цитирование
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Mar 6 2016, 20:47
Сообщение #11


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Цитата
При поочередной передаче флаг приема не может появится после попадания в тело прерывания, иначе как бы мы туда попали

Попали по поводу прерывания от примника, а сбросили флаг передатчика. Как он появился там? Да потому, что передатчик передваал-передавал себе символ, да и передал.

Если не хотите, можете продолжать... и считать допустимой работу "иногда". Как бит в переменно сбрасывается это одно, а как сбросить запрос прерывания в регистре с особенным поведением, это другое. Ситуацию со сбросом лишнего я Вам нарисовал.


Сообщение отредактировал Genadi Zawidowski - Mar 6 2016, 20:49
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 6 2016, 21:03
Сообщение #12


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



да нет. по флагу от передатчика сбрасывается флаг передатчика и по флагу приемника сбрасывается флаг приемника. а если кто остался несброшеным - сбросится перед выходом из прерывания.

я нигде не встречал указания, чтобы для сброса битов регистра SR требовался особый синтаксис, нигде больше не применяемый.
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Mar 6 2016, 21:15
Сообщение #13


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



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

Сообщение отредактировал Genadi Zawidowski - Mar 6 2016, 21:21
Go to the top of the page
 
+Quote Post
firstvald
сообщение Mar 6 2016, 21:28
Сообщение #14


Знающий
****

Группа: Свой
Сообщений: 580
Регистрация: 3-06-08
Пользователь №: 38 041



да сбросятся, но они мне тут не нужны . не в приеме дело - ту эффект вот какой:

я вижу вот что. пробую передать строку из 3 символов (0x30 0x31 0x32 ).

что происходит:
по записи (я все поотключал - таймеры и уарты- оставил только этот уарт) я сейчас с 3 работаю - там код одинаковый
USART3->DR=tx_buf3[tx_ptr3];
на ножку вовсе ничего не передается, но возникает прерывание с выставлением TC . у меня в прерывании честно указатель буфера инкрементируется и в регистр DR записывается следующий байт т е 1. и вот он появляется на ножке. а после выхода из прерывания на передачу отправляется 0 байт из буфера! т е в линии оказывается что нулевой и первый байты оказываются переставленными местами! а вот начиная со следующего прерывания последовательность передачи - правильная.

и я вижу что уходит 0x31 0x30 0x32

вот что происходит в начале - почему переставляется 0 и первый байт местами я понять не могу.

и спасибо огромное за внимание!
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Mar 6 2016, 21:31
Сообщение #15


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Код
acc = SR 0x01
interrupt!
SR=0x03 - появился дополнительный бит
acc = acc & 0xfe = 0x01 & 0xfe = 0x00

SR = 0x00 - сбрасывабтся все биты вообще
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 22:21
Рейтинг@Mail.ru


Страница сгенерированна за 0.0153 секунд с 7
ELECTRONIX ©2004-2016