Jump to content

    

Одноразовый UART в AVR

Вы б отложили чашку с кофейной гущей и гадали бы на Протеусе. Найти обращение к байту в интересующей структуре - дело 5 минут при помощи условных брекпоинтов. Тем более, что дефект у Вас стабильный и танцы с бубном не нада.

Share this post


Link to post
Share on other sites
...А как указать чтобы поля не менялись местами?

 

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

 

Share this post


Link to post
Share on other sites
код видоизменить так, что бы не было в нём первого поля, или последнего. структура как чёрный ящик - длина, начало буфера. тогда пофигу будет где в ней какие поля раскиданы.

А что у вас были случаи когда компилятор менял местами поля в структуре?

Я таких случаев не помню.

Share this post


Link to post
Share on other sites
Полный бред.

1) ADC3_temp = ADC3_RxC_counter;

2) ADC3_temp--;

3) Buf_ADC3[ADC3_temp] = UDR1;

4) ADC3_RxC_counter = ADC3_temp;

5) goto 1

Разумеется после обнуления ADC3_temp команда из п.2 сделает ADC3_temp==0xFF и тогда п.3 сломает память.

Вы, как всегда, пишете быстрее чем думаете.

1 и 4 кпируют волатайл переменную в R16 и далее все операции идут с регистром, что экономит порядка 20 тактов.

5 - ваш глюк.

3 - для одноразовой операции нет разницы, используется указатель или индекс. Всё равно будет с нуля браться адрес и вычисляться смещение.

2 - даже не знаю что и сказать.

 

А про порчу памяти от прерывания вам уже всё сказали. Не возникает лишнего прерывания. И я это вижу в железке на осциллографе, а не в протеусе, что суть кофейная гуща. Да ещё и пиратская (да да, есть такое понятие).

 

Компилятор НИКОГДА не переставит поля структуры. На то она и структура. По крайней мере за 5 лет работы в IAR и 8 лет в CV я такого не видел.

 

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

Это называется массив ;)

Share this post


Link to post
Share on other sites
а не в протеусе, что суть кофейная гуща. Да ещё и пиратская (да да, есть такое понятие).

Как говорят братья-мусульмане, Аллах, когда ночью спит, через стенку не видит :)

Share this post


Link to post
Share on other sites
...компилятор менял местами..

 

для тех кто начал читать топик с конца, даю справку:

 

речь шла не о компиляторах...

 

 

...Это называется массив..

 

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

 

Share this post


Link to post
Share on other sites

Возьмите реализацию очередей из CVAvr-а. Я её и на WinAVR-е "портировал" - работает.

 

Структуры в CvAVR-е передавал, как байтовые массивы:

 

 // Отправка структуры measureData
 pData = (byte *)&measureData;
 for (Uint=0; Uint<sizeof(measureData); Uint ++)
 {
  uartBufferPutchar ( *pData );
  pData ++;
 } // for

 

На компе, в программе на C# принимается как часы ... Даже второй МК (мега8), которая из себя изображает USB, нормально принимает. Там правда свои глюки есть, но то уже издержки эмуляции USB...

Изделие - ваттметр на Мега16, стек - 350 байт.

Edited by hd44780

Share this post


Link to post
Share on other sites
...

1 и 4 кпируют волатайл переменную в R16 и далее все операции идут с регистром, что экономит порядка 20 тактов.

3 - для одноразовой операции нет разницы, используется указатель или индекс. Всё равно будет с нуля браться адрес и вычисляться смещение.

Не суть.

5 - ваш глюк.

А что запретит прерывание по UART_RXC? Если прерывание не запрещены, то при следующем входном байте на UART будет снова вызван обработчик прерывания.

вы так упорото не хотите понять, что индекс массива у вас никак не защищён от переполнения вниз.

А про порчу памяти от прерывания вам уже всё сказали.

так это или не так легко проверить: поставьте проверку на индекс массива

if(ADC2_RxC_counter >= ADCBUFSISE){
    ERROR_LED_ON;
}

Share this post


Link to post
Share on other sites
Возьмите реализацию очередей из CVAvr-а. Я её и на WinAVR-е "портировал" - работает.

 

Советовал уже использовать fifo гдето в первых постах.

У автора топика проблема с заполнением структуры данных АЦП а не с передачей.

Как по мне проглядывается ещё одна проблема - автор пытается заполнять структуру в прерываниях от ацп и одновремененно отправлять её по uart. Возможно там есть временное разделение - т.е. сначала структура заполняется, потом передаётся и гарантированно она не изменится в процессе передачи, но в целом подход неверный.

Было бы правильней проверять флаг необходимости передачи, при обнаружении с запрещёнными прерываниями закинуть всю структуру данных в fifo uart, сбросить флаг необходимости передачи, разрешить прерывания. Заодно можно обнулять индекс массива данных и инкрементировать его по каждому прерыванию ацп.

Share this post


Link to post
Share on other sites
А что запретит прерывание по UART_RXC?

}

UART в режиме SPI. Если байт не будет отправлен, то он не будет принят, и RxC не будет. Посмотрите тушку прерывания - последний байт принимается, но отправки (UDR1 = ADC3_temp;) нет.

Это про порты АЦП речь.

С передачей в комп уже всё определилось - не она виновата.

 

Возьмите реализацию очередей из CVAvr-а. Я её и на WinAVR-е "портировал" - работает.

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

В данном случае маршруты следования информации строго определены, делать очередь нет смысла.

Share this post


Link to post
Share on other sites

Переписал прерывание через указатель, и всё заработало:

unsigned char *pADC3_rx_pointer = &(Buf_ADC3[0]);;
volatile unsigned char ADC3_rx_compl = 0;

//*********

#pragma vector=(0x48*0x02)
__interrupt void ADC3_RxC_isr(void) { // 

 *pADC3_rx_pointer = UDR1;
 if(pADC3_rx_pointer < (&(Buf_ADC3[ADCBUFSISE - 1])) ) {
   pADC3_rx_pointer++;
   UDR1 = 0xff;    
 } else {
   ADC3_rx_compl = 0xff;
 }

}

// **********

while(1) {
if(  ADC3_rx_compl == 0xff  ) {                                                          

     CopyBufFast( (char *)&TransmisionFrame.ADC3[0], (char *)&Buf_ADC3[0], (ADCBUFSISE) );   // êîïèðóåì âðåìåííûé áóôåð â âûõîäíîé ôðåéì 

   pADC3_rx_pointer = &(Buf_ADC3[0]);
   ADC3_rx_compl = 0;
 } 
}

 

Результат:

 

22BB00000002000000000000000000000000000000000003000000000000
0000000000000000DF1A584696F1A500695F1A5F469971A55889A55A
22BB00000003000000000000000000000000000000000004000000000000
00000000000000001A584696F1A4FC695E1A5F469981A55889EDA55A
22BB00000004000000000000000000000000000000000005000000000000
00000000000000001A580696F1A500695E1A5F469971A55889EEA55A
22BB00000005000000000000000000000000000000000006000000000000
00000000000000001A580696E1A4FC695C1A5EC69961A55489F2A55A

 

Пока сделал только для АЦП №3.

 

Теперь думаю, как соптимизировать прерывание. Пробовал избавиться от ADC3_rx_compl и в мейнлупе поставить проверку

if( pADC3_rx_pointer == (&(Buf_ADC3[ADCBUFSISE - 1])) ) {}

Прерывание долбит непрерывно и не останавливается.

Уже поздно и мозг не варит, по тому не могу понять почему :blink:

Share this post


Link to post
Share on other sites
Прерывание долбит непрерывно и не останавливается.

Уже поздно и мозг не варит, по тому не могу понять почему

Если pADC3_rx_pointer изменяется в прерывании, а анлизируется в основном цикле - она должна быть объявлена как volatile-указатель: unsigned char * volatile pADC3_rx_pointer = &(Buf_ADC3[0]);

Share this post


Link to post
Share on other sites

В этом случае компилер ругается

 

Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement

*pADC3_rx_pointer++ = UDR1;

 

Регистры в IAR все volatile и компилер какбЭ намекает, что не может одновременно извлечь две volatile переменные для операции.

 

Хотя в реале, конечно, работает.

Share this post


Link to post
Share on other sites
В этом случае компилер ругается

 

Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement

*pADC3_rx_pointer++ = UDR1;

Вот так

*pADC3_rx_pointer = UDR1;

pADC3_rx_pointer++;

полегчает.

Регистры в IAR все volatile и компилер какбЭ намекает, что не может одновременно извлечь две volatile переменные для операции.

Хотя в реале, конечно, работает.

Компилер намекает, что порядок выполнения присваивания и постинкремента не гарантирован.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this