Bootloader dla zestawu FREEboard – wprowadzenie
Pole instance służy do selekcji konkretnej kopii modułu komunikacyjnego w sytuacji, gdy występują ich dwie lub więcej, np. UART0, UART1 i UART2. Pole pinmuxConfig przechowuje wskaźnik do jednej z funkcji zdefiniowanych w pliku hardware_init_x.c. Przykładowa tablica deskryptorów dla zestawu FREEboard lub FRDM-KL25Z mogłaby wyglądać tak jak poniżej:
const peripheral_descriptor_t g_peripherals[] = {
// UART0
{
.typeMask = kPeripheralType_UART,
.instance = 0,
.pinmuxConfig = uart_pinmux_config,
.controlInterface = &g_uart0ControlInterface,
.byteInterface = &g_uart0ByteInterface,
.packetInterface = &g_framingPacketInterface
},
// I2C0
{
.typeMask = kPeripheralType_I2CSlave,
.instance = 0,
.pinmuxConfig = i2c_pinmux_config,
.controlInterface = &g_i2cControlInterface,
.byteInterface = &g_i2cByteInterface,
.packetInterface = &g_framingPacketInterface
},
// SPI0
{
.typeMask = kPeripheralType_SPISlave,
.instance = 0,
.pinmuxConfig = spi_pinmux_config,
.controlInterface = &g_spiControlInterface,
.byteInterface = &g_spiByteInterface,
.packetInterface = &g_framingPacketInterface
},
#if !BL_MIN_PROFILE
// USB HID
{
.typeMask = kPeripheralType_USB_HID,
.instance = 0,
.pinmuxConfig = NULL,
.controlInterface = &g_usbHidControlInterface,
.byteInterface = NULL,
.packetInterface = &g_usbHidPacketInterface
},
#endif // !BL_MIN_PROFILE
{ 0 } // Terminator
};
Rys. 4. Diagram blokowy komponentów i zależności pomiędzy nimi w architekturze interfejsu peryferia
Struktury, do których wskaźniki są przechowywane w pozostałych trzech polach deskryptora, warto omówić szczegółowo. Pierwszy typ struktury reprezentuje abstrakcyjny interfejs sterujący (abstract control interface):
typedef struct _peripheral_control_interface {
bool (*pollForActivity)(const peripheral_descriptor_t *self);
status_t (*init)(const peripheral_descriptor_t *self, serial_byte_receive_func_t function);
void (*shutdown)(const peripheral_descriptor_t *self);
void (*pump)(const peripheral_descriptor_t *self);
} peripheral_control_interface_t;
Pola danej struktury przechowują wskaźniki do funkcji, które jako pierwszy argument przyjmują wskaźnik do deskryptora peryferia przedstawionego wcześniej:
- pollForActivity() – sprawdza, czy komunikacja została rozpoczęta,
- init() – inicjalizuje sterownik,
- shutdown() – wyłącza sterownik,
- pump() – realizuje dodatkowy czas przetwarzania dla układu peryferyjnego.
Typ status_p występujący jako typ wartości zwracanej w funkcji init() informuje o wyniku przeprowadzonej operacji. Kolejna struktura, typu peripheral_byte_interface_t, reprezentuje abstrakcyjny interfejs bajtowy (abstract byte interface):
typedef struct _peripheral_byte_interface {
status_t (*init)(const peripheral_descriptor_t *self);
status_t (*read)(const peripheral_descriptor_t *self, uint8_t *buffer, uint32_t requestedBytes);
status_t (*write)(const peripheral_descriptor_t *self, const uint8_t *buffer, uint32_t byteCount);
} peripheral_byte_interface_t;
Tak jak poprzednio, elementy powyższej struktury przechowują wskaźniki do następujących funkcji:
- init() – inicjalizuje interfejs,
- read() – przenosi zadaną ilość bajtów z wewnętrznego bufora danych wejściowych do wskazanego bufora zewnętrznego; jest funkcją blokującą, czyli działającą do momentu kiedy zostanie przeniesiona zadana liczba bajtów,
- write() – kopiuje zadaną ilość bajtów ze wskazanego bufora zewnętrznego do wewnętrznego bufora danych wyjściowych.
Trzecia i ostatnia struktura ma typ peripheral_packet_interface_t oraz reprezentuje abstrakcyjny interfejs pakietowy (abstract packet interface):
typedef struct _peripheral_packet_interface {
status_t (*init)(const peripheral_descriptor_t *self);
status_t (*readPacket)(const peripheral_descriptor_t *self, uint8_t **packet, uint32_t *packetLength, packet_type_t packetType);
status_t (*writePacket)(const peripheral_descriptor_t *self, const uint8_t *packet, uint32_t byteCount, packet_type_t packetType);
void (*abortDataPhase)(const peripheral_descriptor_t *self);
status_t (*finalize)(const peripheral_descriptor_t *self);
uint32_t (*getMaxPacketSize)(const peripheral_descriptor_t *self);
void (*byteReceivedCallback)(uint8_t byte);
} peripheral_packet_interface_t;
Interfejs tworzą poniższe funkcje:
- init() – inicjalizuje peryferia,
- readPacket() – odbiera kompletny pakiet przy pomocy wybranego peryferia oraz zwraca dwa wskaźniki: do bufora, w którym zostały zapisane dane wejściowego pakietu, i do zmiennej przechowującej liczbę odebranych bajtów danych; dodatkowy parametr określa czy wejściowy pakiet powinien zawierać dane lub instrukcje,
- writePacket() – wysyła do wybranego peryferia kompletny pakiet utworzony z danych wskazanego bufora zewnętrznego o zadanym wymiarze; parametr packetType decyduje o rodzaju danych w pakiecie (dane lub instrukcje),
- abortDataPhase() – przerywa odbiór pakietów z danymi,
- finalize() – wyłącza peryferia, gdy wszystkie operacje transferu zostaną zakończone,
- getMaxPacketSize() – zwraca maksymalny rozmiar bufora wewnętrznego,
- byteReceivedCallback() – funkcja zwrotna, wywoływana po odebraniu przez interfejs nowego bajtu danych.
Jan Szemiet
Literatura
[1] Demo Application User’s Guide for the FRDM-KL25Z and TWR-KL25Z48 Freescale Platforms
[2] http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=KBOOT

Technologie End of Life i bezpieczeństwo sieci – wyzwania Europy związane z tzw. długiem technologicznym
Najczęstsze błędy firm przy wyborze dostawcy energii i jak ich uniknąć
Fotorezystor, czyli czujnik światła dwojakiego działania. Przykład innowacji w automatyce i elektronice możliwej dzięki technologii fotooporników 



