I dati che stai descrivendo (uso completo a 24 bit della memoria del programma per memorizzare i dati) non possono essere definiti e inizializzati in C e non possono essere letti direttamente tramite C; l'unico modo per accedervi è incapsulare in una funzione di assemblaggio richiamabile in C o intrinseca.
Ci sono davvero due domande qui:
come giocare bene con il compilatore, l'assemblatore e il linker, in modo che quando definisci i tuoi dati a 24 bit in un file di assieme come dati trasferibili con un nome simbolico D1
, piuttosto che dati senza nome a un indirizzo fisso, il compilatore può vedere questa variabile per determinare il suo indirizzo
come accedere ai dati
Alla seconda domanda (come accedere ai dati) viene data risposta per le parti 33EP in DS70613C e si dovrebbe rispondere per le parti 33FJ in DS70204C (ma gli esempi nel manuale 33FJ usano solo i 16 bit bassi). Ecco un esempio di frammento di codice del manuale di riferimento 33EP che funziona per parti 33EP + dovrebbe per 33FJ (non ho un dispositivo 33FJ facilmente disponibile):
(nota: il codice usa int
, mentre sarebbe meglio usare uint16_t
e #include <stdint.h>
)
int prog_data[10] __attribute__((space(prog))) =
{0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999};
unsigned int lowWord[10], highWord[10];
unsigned int tableOffset, loopCount;
int main(void){
TBLPAG = __builtin_tblpage (prog_data);
tableOffset = __builtin_tbloffset (prog_data);
/* Read all 10 constants into the lowWord and highWord arrays */
for (loopCount = 0; loopCount < 10; loopCount ++)
{
lowWord[loopCount] = __builtin_tblrdl (tableOffset);
highWord[loopCount] = __builtin_tblrdh (tableOffset);
tableOffset +=2;
}
while(1)
;
}
Noterai che le funzioni integrate __builtin_tblrdl()
e __builtin_tblrdh()
vengono utilizzate per leggere le parole di dati a 16 bit basse e alte da una posizione di memoria del programma e __builtin_tblpage() and __builtin_tbloffset()
possono essere utilizzate per estrarre la pagina e l'offset dell'indirizzo. In questo esempio particolare, l'array highWord è sempre 0 e l'array lowWord corrisponde ai prog_data definiti e inizializzati in C.
Si prega di notare che qui non vengono utilizzati puntatori! Sebbene sia possibile utilizzare le normali variabili con tag const
, in modo che siano posizionate dal linker nello spazio del programma di sola lettura e in modo da poter leggere la memoria utilizzando tecniche di puntatore C standard, con il compilatore che gestisce automaticamente i registri di paging per te, puoi solo archiviare dati a 16 bit. È necessario accedere alle funzioni integrate TBLRDL e TBLRDH per ottenere tutti i 24 bit di dati.
Per quanto riguarda come giocare bene con il compilatore / linker / ecc, devi ingannare il compilatore e dire che sta vedendo solo dati a 16 bit. Ecco un esempio che ha funzionato per ottenere la variabile D1 dichiarata altrove:
#define D1_SIZE 18
extern uint16_t __attribute__((space(prog))) D1[D1_SIZE];
#define READ_DATA(dst, v, len) readData(dst, __builtin_tblpage(v), __builtin_tbloffset(v), len)
void readData(uint32_t *pdst, uint16_t page, uint16_t offset, uint16_t len)
{
TBLPAG = page;
while (len-- > 0)
{
uint16_t lo = __builtin_tblrdl (offset);
uint16_t hi = __builtin_tblrdh (offset);
*pdst++ = (((uint32_t)(hi)) << 16) | ((uint32_t)(lo));
offset += 2;
}
}
...
uint32_t d1copy[D1_SIZE];
READ_DATA(d1copy, D1, D1_SIZE);
Questo legge correttamente i valori a 24 bit e li memorizza nei 24 bit inferiori di un uint32_t. La variabile D1 esterna dichiarata in C è una variabile fittizia che viene utilizzata solo per ottenere l'indirizzo iniziale sfruttando il modo in cui il compilatore / assemblatore / linker lavorano insieme. Le funzioni integrate gestiscono il resto del lavoro.
Quello che non so è come ottenere automaticamente la dimensione dei dati, dal momento che è definito + inizializzato in assembly.