Estou usando arm gcc (CooCox) para programar uma descoberta STM32F4, e estou lutando com um problema endian
Estou amostrando com um ADC de 24 bits via SPI. Como três bytes estão chegando, primeiro o MSB teve a idéia de carregá-los em uma união para torná-los (eu esperava!) Um pouco mais fácil de usar.
typedef union
{
int32_t spilong;
uint8_t spibytes [4];
uint16_t spihalfwords [2];} spidata;
spidata analogin0;
Carrego os dados usando leituras spi em analogin0.spibytes [0] - [2], com [0] como MSB, depois os cuspo via USART em um megabaud, 8 bits por vez. Sem problemas.
Os problemas começaram quando tentei passar os dados para um DAC de 12 bits. Esse DAC SPI deseja palavras de 16 bits, que consistem em um prefixo de 4 bits começando no MSB, seguido por 12 bits de dados.
As tentativas iniciais foram converter o complemento duplo que o ADC me deu para compensar o binário, xor-analogog0.spihalfwords [0] com 0x8000, deslocando o resultado para os 12 bits inferiores e adicionando o prefixo aritmeticamente.
Incrivelmente frustrante, até eu notar que para analogin0.spibytes [0] = 0xFF e analogin0.spibytes [1] = 0xB5, analogin0.halfwords [0] era igual a 0xB5FF e não 0xFFB5 !!!!!
Depois de perceber isso, parei de usar operações aritméticas e a meia palavra e permaneci na lógica bit a bit e nos bytes
uint16_t temp=0;
.
.
.
// work on top 16 bits
temp= (uint16_t)(analogin0.spibytes[0])<<8|(uint16_t)(analogin0.spibytes[1]);
temp=temp^0x8000; // convert twos complement to offset binary
temp=(temp>>4) | 0x3000; // shift and prepend with bits to send top 12 bits to DAC A
SPI_I2S_SendData(SPI3,temp); //send to DACa (16 bit SPI words)
... e isso funcionou bem. Quando eu espio temp após a primeira linha do código, é 0xFFB5, e não 0xB5FF, então tudo está bem
Então, para perguntas ...
O córtex é novo para mim. Não me lembro da PIC de troca de bytes em int16, embora ambas as plataformas sejam pouco endian. Isso está correto?
Existe uma maneira mais elegante de lidar com isso? Seria ótimo se eu pudesse colocar o ARM7 no modo big endian. Estou vendo muitas referências ao Cortex M4 sendo bi-endiano, mas todas as fontes parecem não me dizer como . Mais especificamente, como coloco o STM32f407 no modo big-endian , ainda melhor se isso puder ser feito no gcc. É APENAS uma questão de definir o bit apropriado no registro do AIRCR? Existem ramificações, como a necessidade de definir o compilador para corresponder ou erros matemáticos mais tarde com bibliotecas inconsistentes?
__REV()
e__REV16()
para reverter bytes.Respostas:
Os sistemas embarcados sempre terão o problema de big endian / little-endian. Minha abordagem pessoal foi sempre codificar a memória interna com a capacidade de endereçamento nativa e fazer qualquer troca correta quando os dados entram ou saem.
Ao carregar [0] como MSB, você codifica o valor como big endian.
Isso indica que o processador é little-endian.
Se, em vez disso, você carregar o primeiro valor em [2] e retornar a [0], codificará o número recebido como little-endian, essencialmente fazendo a troca à medida que o número entra. Depois de trabalhar com a representação nativa, você pode retornar à sua abordagem original de usar operações aritméticas. Apenas certifique-se de devolvê-lo ao big-endian ao transmitir o valor.
fonte
Em relação à recompensa "Realmente quero saber sobre o modo big endian srm32f4", não há modo big endian neste chip. STM32F4 faz todo o acesso à memória em little endian.
O manual do usuário http://www.st.com/web/en/resource/technical/document/programming_manual/DM00046982.pdf menciona isso na página 25. Mas há mais. Na página 93, você pode ver que existem instruções de troca endian. REV e REVB para bit reverso e reverso. O REV mudará a endianess para 32 bits e o REV16 fará isso para os dados de 16 bits.
fonte
Aqui está um trecho de código para um córtex M4, compilado com o gcc
Em C, a chamada pode ser:
Não sei como fazer mais rápido do que isso :-)
fonte
Para o CooCox STM32F429, tudo bem:
...
fonte