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

Данная статья носит характер небольшой заметки, а не учебного пособия.
Одной из особенностей микроконтроллеров Миландр серии 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-- ) { };
/* тут идет мой код
...
*/
}
Спасибо за внимание, исходников не будет, ибо нечего выкладывать.