глюки в AVR-GCC ?

Nov 19, 2004 2 Replies

Привет Всем ! Есть вопросики. Стал опримизировать прогу на С (AVR GCC) и сталкнулся с некоторыми непонятными вещами.



  1. Каким образом закрепить за переменной указателем регистр? Если у нас есть переменная типа char - то все понятно - register unsigned char spiW asm("r3"). Ну а если типа указатель на char ? И я хочу закрепить за регистрами X или Y.
  2. следующий кусок кода: { *(spi_ptr++) = SPDR; SPDR = packCnt; ++packCnt; } ассемблируется в следующий код (с флагом оптимизации -O3) { *(spi_ptr++) = SPDR; 28e: 7f b1 in r23, 0x0f ; 15 290: 71 93 st Z+, r23 292: f0 93 61 00 sts 0x0061, r31 296: e0 93 60 00 sts 0x0060, r30 SPDR = packCnt; Хотя spi_ptr обьявлен как volatile unsigned char *spi_ptr. Почему же он не обнавляется на каждом витке цикла ? Тоесть в прерываниях я изменяю spi_ptr, а реально он не меняется :( В чём же дело ?
  3. В том же куске кода непонятно что будет, если произойдет прерывание между инструкциями sts 0x0061, r31 и sts 0x0060, r30 ? тоесть в ячейке

0x0061 будет новое значение (записаное по прерыванию), а в 0x0060 - старое ? Как же быть ? P.S. у меня avr-gcc (GCC) 3.4.1 Спасибо за исчерпывающие ответы :)
19-Nov-04 16:46 Alexy Gorbach wrote to All:

AG> 1. Каким образом закрепить за переменной указателем регистр? Если у нас AG> есть переменная типа char - то все понятно - register unsigned char spiW AG> asm("r3"). Ну а если типа указатель на char ? И я хочу закрепить за AG> регистрами X или Y. Не знаю, такими вещами не баловался.

AG> 2. следующий кусок кода: AG> { AG> *(spi_ptr++) = SPDR;

AG> Хотя spi_ptr обьявлен как volatile unsigned char *spi_ptr. Почему же он AG> не обнавляется на каждом витке цикла ? Одно из распространённых заблуждений. Аналогичное легендам про const char *ptr и char const *ptr :-)

В данном случае volatile относится не к spi_ptr, а к (*spi_ptr). Т.е. volatile - та ячейка, на которую указывает указатель.

Для volatile-указателя надо написать

unsigned char * volatile spi_ptr;

AG> 3. В том же куске кода непонятно что будет, если произойдет прерывание AG> между инструкциями sts 0x0061, r31 и sts 0x0060, r30 ? тоесть AG> в ячейке AG> 0x0061 будет новое значение (записаное по прерыванию), а в 0x0060 - AG> старое ? Как же быть ? Ручками заводит критическую секцию (запрещат все для простоты или только нужное прерывание на время как доставания указателя в регистр, так и записи его назад). В языке C слово volatile только говорит компилятору о том, что переменная может измениться "неожиданно" и нельзя оптимизировать обращения к ней за счёт кеширования в регистрах. На проблемы неатомарных операций и прерываний действие volatile не распространяется.

AG> P.S. у меня avr-gcc (GCC) 3.4.1 Вопросы 2 и 3 должны иметь одинаковые ответы для любого C-компилятора. (а не компилятора С-подобного языка, все тонкости которого известны только авторам компилятора).

wbr,

AG> 2. следующий кусок кода: AG> { AG> *(spi_ptr++) = SPDR; AG> SPDR = packCnt; AG> ++packCnt; AG> } AG> ассемблируется в следующий код (с флагом оптимизации -O3) { AG> *(spi_ptr++) = SPDR; AG> 28e: 7f b1 in r23, 0x0f ; 15 AG> 290: 71 93 st Z+, r23 AG> 292: f0 93 61 00 sts 0x0061, r31 AG> 296: e0 93 60 00 sts 0x0060, r30 AG> SPDR = packCnt; AG> Хотя spi_ptr обьявлен как volatile unsigned char *spi_ptr. Почему же он AG> не обнавляется на каждом витке цикла ?

А что по-твоему делается в адресах 290, 292 и 296?

AG> Тоесть в прерываниях я изменяю AG> spi_ptr, а реально он не меняется :( В чём же дело ? AG> 3. В том же куске кода непонятно что будет, если произойдет прерывание AG> между инструкциями sts 0x0061, r31 и sts 0x0060, r30 ? тоесть в ячейке AG> 0x0061 будет новое значение (записаное по прерыванию), а в 0x0060 - AG> старое ? Как же быть ?

volatile от прерываний не помогает (никто и не обещал...) Hужен отдельный вид блокировки, в данном случае проще на пару команд запретить все прерывания.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required