Modułu FRDM-KL25Z raczej nie muszę nikomu przedstawiać, bo na pewno wszyscy znają je przynajmniej z widzenia lub reklamy. Wspomnę jednak, że moduł ten jest mechanicznie zgodny z Arduino UNO. Ta zgodność spowodowała, że musiałem się zmierzyć z problemem, który początkowo wydawał się być niezwykle poważny. Ok, ale od początku. Zgodność mechaniczna zachęciła mnie do zamontowania wyświetlacza TFT na "freedomce". Pasuje wspaniale, ale... No właśnie, ale.
Pech chciał, że projektant obwodu drukowanego "freedomki" umieścił jeden z sygnałów (pinów) procesora w zewnętrznym rzędzie pinów, który to właśnie zapewnia mechaniczną zgodność z Arduino. O który pin chodzi? Dokładnie o ten:
Jest to pin PTA4, którego domyślną funkcją tuż po włączeniu zasilania jest wywoływanie przerwania niemaskowalnego (NMI). Przerwanie to wywoływane jest, gdy na pinie pojawi się stan niski. Pewnie już się domyślacie, że to będzie sprawiało problemy... Przecież niektóre shieldy Arduino mogą mieć w tym miejscu rezystor do GND!
Tak też było w momencie zaaplikowania wyświetlacza do freedomki. Procek się zamrażał, debugger milczał, bo nie potrafił się połączyć z układem docelowym... i właściwie można było pomyśleć, że coś uległo uszkodzeniu. W tym konkretnym przypadku głównym winowajcą okazały się bufory 74HC245 dopasowujące poziomy napięć do akceptowalnych przez kontroler wyświetlacza, gdy korzystamy z tradycyjnej płytki Arduino UNO. Sposób przeróbki wyświetlacza pokażę nieco później, a teraz skupię się na kompleksowym rozwiązaniu problemu. Najpierw przedstawię krótki programik do migania diodą pozbawiony obsługi pinu PTA4:
Kod: Zaznacz cały
#include <stdbool.h>
#include "mcu.h"
#define RED_LED_PIN 18
int main(void)
{
volatile uint32_t loop;
//podłączam zegar do portu B
SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK);
//ustawiam wyjcie na pinie 18 portu B
PTB->PDDR |= (1ul << RED_LED_PIN);
//ustawiam tryb pracy tego pinu. 1 oznacza tryb GPIO
PORTB->PCR[RED_LED_PIN] = PORT_PCR_MUX(1);
while(true)
{
//maa ptelka opóźniajca, bym widział miganie diody
for(loop = 0; loop < 500000; ++loop);
//zmiana stanu na pinie. Tzw. toggle
PTB->PTOR = (1ul << RED_LED_PIN);
}
}
Po załadowaniu tego programu do procka oraz sprowokowaniu NMI w taki sposób:
Freedomka przestała odpowiadać, a program się nie wykonywał. Po przejrzeniu dokumentacji doszedłem do wniosku, że skoro nie da się zamaskować NMI, bo przecież to jest niemaskowalne przerwanie, należy je najzwyczajniej w świecie obsłużyć. Cały myk polega na tym, że wewnątrz obsługi tego przerwania zmieniam tryb pracy pinu PTA4 na zwykły GPIO o kierunku wejściowym oraz kasuję flagę przerwania poprzez jej odczyt. Ot, cała filozofia... Proste, prawda? Nasiedziałem się nad tym... A oto zmodyfikowana wersja migacza diodowego:
Kod: Zaznacz cały
#include <stdbool.h>
#include "mcu.h"
#define RED_LED_PIN 18
void NMI_Handler(void);
int main(void)
{
volatile uint32_t loop;
//podłączam zegar do portu B
SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK);
//ustawiam wyjcie na pinie 18 portu B
PTB->PDDR |= (1ul << RED_LED_PIN);
//ustawiam tryb pracy tego pinu. 1 oznacza tryb GPIO
PORTB->PCR[RED_LED_PIN] = PORT_PCR_MUX(1);
while(true)
{
//maa ptelka opóźniajca, bym widział miganie diody
for(loop = 0; loop < 500000; ++loop);
//zmiana stanu na pinie. Tzw. toggle
PTB->PTOR = (1ul << RED_LED_PIN);
}
}
//obsługa przerwania niemaskowalnego
void NMI_Handler(void)
{
//podłączam zegar do portu A
SIM->SCGC5 |= (SIM_SCGC5_PORTA_MASK);
//odczytując stan flagi przerwania automatycznie ją kasuję
if(PORTA->PCR[4] &PORT_PCR_ISF_MASK)
{
;//nic nie robię
}
//bezwarunkowo przełączam pin PTA4 (NMI) w tryb GPIO
//domyślnie po resecie ten pin będzie wejściem
PORTA->PCR[4] = PORT_PCR_MUX(1);
//i tyle...po bólu :-)
}
Od teraz pin PTA4 nie będzie nam już sprawiał problemów!
Ok, a miałem jeszcze pokazać, jak przerobiłem wyświetlacz. Kilka słów wyjaśnienia. Pin wyświetlacza oznaczony jako RD steruje przy okazji kierunkiem pracy buforów 74HC245. Gdy stan na pinie RD jest niski, bufory są w trybie wyjściowym, co powoduje, że na ich wyjściach są stany niskie (tak, tak, właśnie...). Wystarczy pin RD podciągnąć rezystorem do 3V3 i już mamy święty spokój, a freedomka się nie zamraża.
Tak to wygląda przed przeróbką:
Po zamontowaniu rezystora:
Oraz zmontowany na nowej taśmie piankowej:
No i na koniec efekt działania na freedomce:
Mam nadzieję, że opis jest klarowny i nikt nie będzie miał kłopotu z okiełznaniem NMI, ale w razie czego proszę śmiało pytać.
Pozdrawiam!