Imprimir caracteres variáveis ​​no UART não funciona, as constantes funcionam bem

9

Eu tenho um problema bastante estranho com o XC8 em um microcontrolador PIC18F27K40. Em um PIC16F1778, ele funciona . Eu defini:

void uart_putch(unsigned char byte) {
    while (!PIR3bits.TX1IF);
    TX1REG = byte;
}

Quando, no meu mainloop, eu ligo uart_putch('a');, isso funciona bem. No entanto, quando eu defino const char c = 'a';e ligo uart_putch(c);, ele não funciona. Ele imprime algo, embora não seja a- eu acho que eles são 0x00personagens, dos quais eu recebo hexdump -x /dev/ttyUSB0. Este não é um problema com a porta serial no meu computador; Eu olhei com um escopo e o sinal é diferente (a esquerda funciona, a direita não):

insira a descrição da imagem aqui

O código é simples:

void main(void) {
    init(); // Sets up ports and UART control registers
    while (1) {
        uart_putch('a'); // or c
    }
}

O que não quer trabalhar é usando qualquer uma das funções de cordas ( puts, printf, etc.), que acho que está relacionado - assim nessa questão eu fiz um exemplo de trabalho mínimo com caracteres.

O assembly gerado quando uso uma variável cpossui:

_c:
    db  low(061h)
    global __end_of_c

_main:
    ; ...
    movlw   low((_c))
    movwf   tblptrl
    if  1   ;There is more than 1 active tblptr byte
    movlw   high((_c))
    movwf   tblptrh
    endif
    if  1   ;There are 3 active tblptr bytes
    movlw   low highword((_c))
    movwf   tblptru
    endif
    tblrd   *
    movf    tablat,w
    call    _putch

E com uma constante que tem no _mainbloco:

    movlw   (061h)&0ffh 
    call    _putch

Estou usando o Compilador MPLAB XC8 C V1.41 (24 de janeiro de 2017), com a versão de suporte da parte 1.41.

As partes relevantes do meu Makefile:

CC:=xc8
CFLAGS:=-I. --chip=18F27K40 -Q -Wall

SRC:=main.c uart.c
DEP:=uart.h
PRS:=$(subst .c,.p1,$(SRC))
OBJ:=main.hex

all: $(OBJ)

$(OBJ): $(PRS)
    $(CC) $(CFLAGS) $^

$(PRS): %.p1: %.c $(DEP)
    $(CC) $(CFLAGS) -o$@ --pass1 $<

Qualquer ajuda para conseguir esse trabalho seria muito apreciada.


fonte
11
Defina seu uart_putch como "uart_putch (const char & c)". Isso é chamado de "passagem por referência".
Rohat Kılıç
11
@ RohatKılıç Isso é C ++
TisteAndii
11
@ Crosley eu pretendia incluir isso, desculpe. Não faz diferença (ainda não funciona). Eu tentei tudo unsigned char, char, const unsigned chare const char.
11
Na sua definição de putch (), o que acontece se você renomear o argumento byteTx? Estou preocupado que bytepossa ser definido em outro lugar como um tipo de dados. (Parece que isso geraria um diagnóstico do compilador, mas claramente algo estranho está acontecendo aqui.) E como outro teste, ele se putch(0x61)comporta mal da mesma maneira que putch('a')? Gostaria de saber se a instrução de leitura da tabela está lendo dados de 8 ou 16 bits. O registro PIC W é de apenas 8 bits, certo?
precisa saber é
2
@ MarkU, então eu tentei em um PIC16F1778 e lá a mesma coisa funciona bem. (o que o torna um problema muito menos ruim para mim, pois eu estou bem com qualquer um dos chips, mas ainda assim eu gostaria de saber como fazer com que o 18F27K40 funcione ..)

Respostas:

3

Seu programa está bom, é um bug no PIC18F27K40.

Veja http://ww1.microchip.com/downloads/en/DeviceDoc/80000713A.pdf

Use o compilador XC8 V1.41 e o mplabx IDE, selecione Opções globais do XC8 / vinculador XC8 e selecione "Opções adicionais"; em seguida, adicione +nvmrega caixa Errata e tudo ficará bem.

Trecho do documento vinculado, palavras-chave marcadas em negrito:

O TBLRD requer que o valor NVMREG aponte para a memória apropriada

As revisões de silicone afetadas dos dispositivos PIC18FXXK40 incorretamente exigem que os NVMREG<1:0>bits no NVMCONregistro sejam configurados para TBLRDacesso às várias regiões da memória. O problema é mais aparente nos programas C compilados quando o usuário define um tipo const e o compilador usa TBLRDinstruções para recuperar os dados da memória Flash do programa (PFM). O problema também é aparente quando o usuário define uma matriz na RAM para a qual o complier cria um código de inicialização, executado anteriormente main(), que usa TBLRDinstruções para inicializar a RAM a partir do PFM.

Ian Munro
fonte
2

const chars são armazenados na memória do programa (flash), e parece que o compilador está vendo que você não o está usando como variável (já que nunca muda) e otimizando-o na memória do programa, independentemente de você usar const ou não.

Tente declarar como volatile char c= 'a';. Isso o forçará a ser armazenado na SRAM em vez de flash.

Por que isso importa?

Nos PIC18s, o uso da diretiva db (databyte para armazenar um byte na memória do programa) com um número ímpar de bytes (como no seu caso) irá preenchê-lo automaticamente com zeros. Esse comportamento difere do PIC16, provavelmente o motivo pelo qual ele trabalha em um, mas não no outro. Por esse motivo, as strings ou caracteres armazenados na memória flash também não funcionarão com nenhuma das funções padrão de strings, como strcpy ou printf. Armazenar algo na memória do programa não é automaticamente um tipo seguro.

Com base na montagem, é bem claro que está carregando os 8 bytes incorretos. Que é 0x00, por isso está enviando corretamente 0x00 (como você confirmou completamente).

Pode ser difícil prever o que você obterá com a quantidade insana de otimização do compilador atualmente, então não tenho certeza se isso funcionará. o truque volátil deve funcionar, mas se você realmente quiser armazená-lo em flash, tente o seguinte:

TXREG = data & 0xff;

ou possivelmente

TXREG = data & 0x0ff;

Eu sei que, em teoria, isso não deve fazer nada. Mas estamos tentando alterar a saída de montagem do compilador para fazer o que queremos, e não meio que, mas não realmente o que queremos.

No Guia do Usuário do MPASM:

insira a descrição da imagem aqui

Também recomendo conferir você mesmo , bem como o code_pack, no PDF. P. 65.

metacolina
fonte