Los datos que está describiendo (uso total de 24 bits de la memoria del programa para almacenar datos) no se pueden definir e inicializar en C, y no se pueden leer directamente a través de C; la única forma de acceder es encapsulando en una función de ensamblaje invocable en C o en una función intrínseca.
Realmente hay dos preguntas aquí:
cómo jugar bien con el compilador, ensamblador y enlazador, de modo que cuando defina sus datos de 24 bits en un archivo de ensamblaje como datos reubicables con un nombre simbólico D1
, en lugar de datos sin nombre en una dirección fija, el compilador puede ver esta variable para determinar su dirección
cómo acceder a los datos
La segunda pregunta (cómo acceder a los datos) se responde para las partes 33EP en DS70613C y se debe responder para las partes 33FJ en DS70204C (pero los ejemplos en el manual 33FJ solo usan los 16 bits bajos). Aquí hay un fragmento de código de ejemplo del manual de referencia 33EP que funciona para las partes 33EP + debería para 33FJ (no tengo un dispositivo 33FJ fácilmente disponible):
(nota: el código usa int
, mientras que sería mejor usar uint16_t
y #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)
;
}
Notará que las funciones incorporadas __builtin_tblrdl()
y __builtin_tblrdh()
se utilizan para leer las palabras de datos de 16 bits altas y bajas de una ubicación de memoria del programa, y __builtin_tblpage() and __builtin_tbloffset()
se pueden usar para extraer la página y el desplazamiento de la dirección. En este ejemplo particular, la matriz highWord siempre es 0, y la matriz lowWord coincide con los prog_data definidos e inicializados en C.
¡Tenga en cuenta que no se utilizan punteros aquí! Aunque es posible utilizar variables normales con las que está etiquetado const
, de modo que el enlazador las ubique en el espacio del programa de solo lectura, y para que pueda leer la memoria utilizando técnicas de puntero C estándar, con el compilador administrando automáticamente los registros de paginación para usted, solo puede almacenar datos de 16 bits. Debe acceder a las funciones incorporadas TBLRDL y TBLRDH para obtener los 24 bits de datos.
En cuanto a cómo jugar bien con el compilador / enlazador / etc., debe engañar al compilador y decirle que solo está viendo datos de 16 bits. Aquí hay un ejemplo que funcionó para llegar a la variable D1 declarada en otro lugar:
#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);
Esto lee correctamente los valores de 24 bits y los almacena en los 24 bits inferiores de un uint32_t. La variable externa D1 declarada en C es una variable ficticia que solo se utiliza para llegar a la dirección inicial aprovechando la forma en que el compilador / ensamblador / enlazador trabaja en conjunto. Las funciones integradas manejan el resto del trabajo.
Lo que no sé es cómo obtener automáticamente el tamaño de los datos, ya que está definido + inicializado en el ensamblaje.