Управление выводами порта совмещенного с JTAGом.

Управление выводами портов MDR_PORTB и MDR_PORTD, при использовании отладочного интерфейса JTAGA и/или JTAGB. Глюки JTAG. Что делать если отваливается JTAG.

Cover Image

Данная статья носит характер небольшой заметки, а не учебного пособия.

Одной из особенностей микроконтроллеров Миландр серии 9х (точно знаю о 92, 93 с которыми работаю), на мой взгляд, это не совсем продуманная организации управления портами ввода вывода, а именно отсутствие привычных для пользователей stm32 регистров BRR и BSRR, которые позволяют атомарно устанавливать и сбрасывать их состояние. Соответственно необходимо выполнять команды чтение-модификация-запись, что в принципе приемлемо, но...

Для установке состояния вывода порта используется регистр RXTX, значит нужно выполнить следующие операции:

// Сброс вывода 9 порта B
MDR_PORTB->RXTX &= ~(PORT_Pin_9);
// Установка вывода 9 порта B
MDR_PORTB->RXTX | = PORT_Pin_9; 

В принципе всё логично и просто. Однако если вы используете JTAGA, который висит на порте B, программа работать будет, но при выполнении этих команд отладка отвалится. Любителям SPL повезло больше в функциях PORT_SetBits и PORT_ResetBits уже продумано это поведение, но об этом позже.

В первый раз столкнувшись с таким поведением я был несколько озадачен. Тела функций PORT_SetBits и PORT_ResetBits конечно же рассмотрел в первую очередь, но данное решение показалось слишком сложным. В итоге понадеялся на Bit-band регионы. Оказалось что и здесь есть подводный камень. Bit-band хоть и позволяет атомарно установить или сбросить нужный бит, но выполняет такие же операции чтения-модификации-записи, хоть и на аппаратном уровне.

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

Что в итоге получилось:

// Макроопределение порта используемого для JTAG
#define PORT_JTAG MDR_PORTB 

__forceinline void PORT_JTAG_SetBits ( uint32_t PORT_Pin )
{
    PORT_JTAG->RXTX = PORT_Pin | (PORT_JTAG->RXTX & 0xFFE0 ));
}

__forceinline void PORT_JTAG_ResetBits( uint32_t PORT_Pin )
{
    PORT_JTAG->RXTX &= ~(PORT_Pin | 0x001F);
}

Основная идея это в "занулении" выводов JTAG, то есть принудительная установка их в логический 0.

И ещё один хак, который предложили участники форума Миландр, для большего удобства отладки, на случай если вдруг JTAG всё-таки отвалится, вставляйте в начало программы, прям сразу первой строчкой в main не большую задержку, это позволит хотя бы подключиться к чипу для его стирания.

int main (void)
{
    uint32_t  timeout = 0xfffff; // Счетчик времени ожидания
    // ===== Инициализация начальных значений переменных ============
    /*
        Задержка необходима для не допущения блокировки кристалла во время нормальной работы программы.
        Начинать программировать кристалл необходимо во время действия цикла.
        Нажали СБРОС, потом начали программировать.
    */
    while( timeout-- ) { };

    /* тут идет мой код

    ...

    */
}

Спасибо за внимание, исходников не будет, ибо нечего выкладывать.