Os dados que você está descrevendo (uso completo de 24 bits da memória do programa para armazenar dados) não podem ser definidos e inicializados em C e não podem ser lidos diretamente via C; a única maneira de acessá-lo é encapsulando em uma função de montagem chamada C ou intrínseca.
Há realmente duas perguntas aqui:
como jogar bem com o compilador, o assembler e o vinculador, para que quando você defina seus dados de 24 bits em um arquivo de assembly como dados relocáveis com um nome simbólico D1
, em vez de dados não nomeados em um endereço fixo, o compilador possa ver essa variável para determinar seu endereço
como acessar os dados
A segunda pergunta (como acessar os dados) é respondida pelas partes 33EP no DS70613C e deve ser respondida pelas partes 33FJ no DS70204C (mas os exemplos no manual 33FJ usam apenas os baixos 16 bits). Aqui está um exemplo de trecho de código do manual de referência da 33EP que funciona para as peças da 33EP + deveria para a 33FJ (não tenho um dispositivo 33FJ facilmente disponível):
(nota: o código usa int
, ao passo que seria melhor usar 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)
;
}
Você notará que o builtin funciona __builtin_tblrdl()
e __builtin_tblrdh()
é usado para ler as palavras baixas e altas de 16 bits dos dados de um local de memória do programa e __builtin_tblpage() and __builtin_tbloffset()
pode ser usado para extrair a página e o deslocamento do endereço. Neste exemplo em particular, a matriz highWord é sempre 0 e a matriz lowWord corresponde aos dados prog_data definidos e inicializados em C.
Observe que nenhum ponteiro é usado aqui! Embora seja possível usar variáveis normais marcadas com const
, para que elas estejam localizadas pelo vinculador no espaço de programa somente leitura e para que você possa ler a memória usando técnicas padrão de ponteiro C, com o compilador gerenciando automaticamente os registros de paginação para você, você só pode armazenar dados de 16 bits. Você precisa acessar as funções internas TBLRDL e TBLRDH para obter todos os 24 bits de dados.
Quanto a como jogar bem com o compilador / vinculador / etc, você precisa enganar o compilador e dizer que ele está apenas vendo dados de 16 bits. Aqui está um exemplo que funcionou para obter a variável D1 declarada em outro 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);
Isso lê corretamente os valores de 24 bits e os armazena nos 24 bits inferiores de um uint32_t. A variável D1 externa declarada em C é uma variável fictícia que é usada apenas para obter o endereço inicial, aproveitando a maneira como o compilador / montador / vinculador trabalha em conjunto. As funções internas lidam com o restante do trabalho.
O que eu não sei é como obter automaticamente o tamanho dos dados, pois eles são definidos + inicializados na montagem.