Se il file di intestazione fornito da un venditore di qualcosa con cui il proprio codice deve interagire è carente in qualche modo, in quali casi è meglio:
- aggirare le carenze dell'intestazione nel codice principale
- Copia il file di intestazione nel progetto locale e risolvilo
- Correggi il file di intestazione nel punto in cui è memorizzato come strumento fornito dal fornitore
- Correggi il file di intestazione nel punto centrale, ma crea anche una copia locale e prova ad avere sempre le due corrispondenze
- Fai qualcos'altro
Ad esempio, il file di intestazione fornito da ST Micro per la serie STM320LF contiene le linee:
typedef struct
{
__IO uint32_t MODER;
__IO uint16_t OTYPER;
uint16_t RESERVED0;
....
__IO uint16_t BSRRL; /* BSRR register is split to 2 * 16-bit fields BSRRL */
__IO uint16_t BSRRH; /* BSRR register is split to 2 * 16-bit fields BSRRH */
....
} GPIO_TypeDef;
Nell'hardware e nella documentazione dell'hardware, BSRR è descritto come un singolo registro a 32 bit. Circa il 98% delle volte che si vuole scrivere su BSRR, si sarà interessati solo a scrivere la metà superiore o la metà inferiore; è quindi conveniente poter usare BSSRH e BSSRL come mezzo per scrivere metà del registro. D'altra parte, ci sono occasioni in cui è necessario che l'intero registro a 32 bit sia scritto come una singola operazione atomica. Il modo "ottimale" di scriverlo (mettendo da parte i problemi di spaziatura bianca) sarebbe:
typedef struct
{
__IO uint32_t MODER;
__IO uint16_t OTYPER;
uint16_t RESERVED0;
....
union // Allow BSRR access as 32-bit register or two 16-bit registers
{
__IO uint32_t BSRR; // 32-bit BSSR register as a whole
struct { __IO uint16_t BSRRL, BSRRH; };// Two 16-bit parts
};
....
} GPIO_TypeDef;
Se la struttura è stata definita in questo modo, il codice potrebbe utilizzare BSRR quando necessario per scrivere tutti i 32 bit o BSRRH / BSRRL quando si scrivono 16 bit. Dato che l'intestazione non è così, sarebbe meglio usare l'intestazione come-è, ma applicare un icky typecast nel codice principale scrivendo ciò che sarebbe scritto in modo idioma come thePort->BSRR = 0x12345678;
come *((uint32_t)&(thePort->BSSRH)) = 0x12345678;
, o sarebbe essere meglio usare un file di intestazione con patch? Se quest'ultimo, dove dovrebbe essere archiviato il file con patch e come dovrebbe essere gestito?
Modifica
Nel file di dati di questo fornitore, i registri di dispositivi I / O sono definiti utilizzando definizioni di struttura come sopra con definizioni di macro come #define GPIOB (*((struct GPIO_TypeDef*)GPIO_BASE + 0x100))
. Poiché GPIOA
, GPIOB
ecc. Sono definiti come macro piuttosto che identificatori, qualsiasi sostituzione macro di GPIO_TypeDef
che diventa effettiva dopo che la struttura è stata definita influenzerà gli usi futuri di quel tipo ma si applicherà anche a GPIOA
, GPIOB
, ecc. Quindi, la mia inclinazione attuale sarebbe quella di definire il mio file di intestazione a livello di progetto che #include
s è il file del venditore, e quindi definisce la mia struttura e macro-sostituti il nome della mia struttura per il venditore. Ciò consentirebbe al codice di essere scritto di utilizzare i registri nel normale modo idiomatico mentre si utilizzano le definizioni fornite dal fornitore per quasi tutto il resto e pur fornendo un chiaro punto di patch.