Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ADuC7128 + IAR C 5.11
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Dir
Итак, ADuC7128 + C от IAR v5.11. Тестовая и программирующая аппаратура J-Link v3.78d (JetLink-5) . Проблема с отработкой обычного кольцевого буфера по прерываниям. Одна программа putBYTE() пишет в этот буфер, а по прерыванию от таймера этот буфер выгребается и посылается на UART. Период прерываний от таймера 50мкс, UART настроен на скорость 115200.
Вот ее текст:

Код
typedef unsigned char BYTE;
#define TX_BUFFER_SIZE0 64
#define    COM_TEMP 6    // COMxTX Empty
volatile BYTE tx_buffer0[TX_BUFFER_SIZE0];
volatile char tx_wr_index0, tx_rd_index0, tx_counter0;

void putBYTE0(BYTE c)
{
    while (tx_counter0 == TX_BUFFER_SIZE0);
    tx_buffer0[tx_wr_index0] = c;
    if (++tx_wr_index0 == TX_BUFFER_SIZE0)
        tx_wr_index0=0;
    tx_counter0++;
}

__arm __irq void IRQ_Handler(void)
{
    if (IRQSTA & (1 << INT_T0))            // сброс прерывания от таймера
        T0ICLR = 0;

BYTE status;
    status = COM0STA0;
    if (status & (1 << COM_TEMP))
    {
        if (tx_counter0)
        {
           tx_counter0--;                                                        // 1
           COM0TX = tx_buffer0[tx_rd_index0];
           if (++tx_rd_index0 == TX_BUFFER_SIZE0)               // 2
               tx_rd_index0=0;
// test -------
           if (!tx_counter0 && (tx_rd_index0 != tx_wr_index0))
                   LED_OFF;
// test -------
        }
    }
}

Глюк в том, что в передатчик UART иногда посылается на 1 байт больше! Этот факт отражен в тестовом фрагменте между двумя // test. Т.е. при уменьшении tx_counter до 0, tx_rd_index0 становится больше (на 1), чем tx_wr_index0.
Так реально и происходит. ПК получает лишний байт, стоящий за буфером. Бряк, останавливающий Jet-Lin и поставленный на макрос LED_OFF, показывает в Watch, что tx_rd_index = tx_wtr_index+1 (с учетом, естественно закольцовки буфера). Дальше идет, как и положено, полная ерунда sad.gif
Что тут не так? В п/п putBYTE() инкремент tx_counter0 идет самым последним, так что, вроде, ни о какой атомарности и необходимости запрещать прерывания речи не идет. Хотя ХЗ.
HELP!!!
PS. Вся оптимизация выключена. Даже не LOW, а NO. Хотя при LOW-уровне было тоже самое.
aaarrr
Цитата(Dir @ Feb 18 2008, 11:36) *
В п/п putBYTE() инкремент tx_counter0 идет самым последним, так что, вроде, ни о какой атомарности и необходимости запрещать прерывания речи не идет. Хотя ХЗ.

Почему это? Прерывание вполне может случиться в момент, когда tx_counter0 уже ++, но еще не записан - получите лишний байт.
vmp
Цитата(Dir @ Feb 18 2008, 11:36) *
В п/п putBYTE() инкремент tx_counter0 идет самым последним, так что, вроде, ни о какой атомарности и необходимости запрещать прерывания речи не идет. Хотя ХЗ.

На ARM'е инкремент операция не атомарная, состоит из 3 команд - загрузка, инкремент, сохранение. Если прерывание вклинится между ними - получаем рассогласование.
Dir
Цитата(aaarrr @ Feb 18 2008, 10:40) *
Почему это? Прерывание вполне может случиться в момент, когда tx_counter0 уже ++, но еще не записан - получите лишний байт.


Вообще то не лишний, а наоборот одного байта не будет до поры до времени. Но, ИМХО, не в этом проблема.

Цитата(vmp @ Feb 18 2008, 10:42) *
На ARM'е инкремент операция не атомарная, состоит из 3 команд - загрузка, инкремент, сохранение. Если прерывание вклинится между ними - получаем рассогласование.


И это нужно делать руками (т.е. запрещать прерывания)? Встроенных средств в компилере для этого нет?
aaarrr
Цитата(Dir @ Feb 18 2008, 11:55) *
Вообще то не лишний, а наоборот одного байта не будет до поры до времени. Но, ИМХО, не в этом проблема.

Да нет, именно лишний: в прерывании tx_counter уменьшится на 1, а после выхода перезапишется инкрементированным значением.

Цитата(Dir @ Feb 18 2008, 11:55) *
И это нужно делать руками (т.е. запрещать прерывания)? Встроенных средстd в компилере для этого нет?

Руками.
vmp
Цитата(Dir @ Feb 18 2008, 11:55) *
И это нужно делать руками (т.е. запрещать прерывания)? Встроенных средстd в компилере для этого нет?

Есть ключевое слово __monitor. Но оно запрещает прерывание на всю функцию.

Кстати, светодиод может гаснуть, если прерывание пройдет между инкрементом tx_wr_index0 tx_counter0.
Dir
Цитата(vmp @ Feb 18 2008, 11:03) *
Есть ключевое слово __monitor. Но оно запрещает прерывание на всю функцию.

Кстати, светодиод может гаснуть, если прерывание пройдет между инкрементом tx_wr_index0 tx_counter0.


Спасибо, vmp и aaarrr!
Заработало biggrin.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.