La stampa di caratteri variabili su UART non funziona, le costanti funzionano correttamente


9

Ho un problema piuttosto strano con XC8 su un microcontrollore PIC18F27K40. Su un PIC16F1778 funziona . Ho definito:

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

Quando, nel mio mainciclo, chiamo uart_putch('a');, funziona benissimo. Tuttavia, quando definisco const char c = 'a';e chiamo uart_putch(c);, non funziona. Stampa qualcosa, sebbene non un a- penso che siano 0x00personaggi, da cui ottengo hexdump -x /dev/ttyUSB0. Questo non è un problema con la porta seriale sul mio computer; Ho guardato con un ambito e il segnale è diverso (sinistra funziona, destra no):

inserisci qui la descrizione dell'immagine

Il codice è semplice:

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

Che cosa non funziona né è utilizzando una delle funzioni stringa ( puts, printf, ecc), che credo sia correlata - così a questa domanda ho fatto un esempio di lavoro minimo con caratteri.

L'assembly generato quando uso una variabile cha:

_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 con una costante ha nel _mainblocco:

    movlw   (061h)&0ffh 
    call    _putch

Sto usando MPLAB XC8 C Compiler V1.41 (24 gennaio 2017), con supporto per parti versione 1.41.

Le parti rilevanti del mio 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 $<

Qualsiasi aiuto per farlo funzionare sarebbe molto apprezzato.


1
Definisci il tuo uart_putch come "uart_putch (const char & c)". Questo si chiama "passaggio per riferimento".
Rohat Kılıç,

1
@ RohatKılıç Questo è C ++
TisteAndii,

1
@tcrosley intendevo includerlo, scusa. Non fa differenza (continua a non funzionare). Ho provato tutto unsigned char, char,const unsigned char e const char.

1
Nella tua definizione di putch (), cosa succede se rinomini l'argomento byteTx? Temo che bytepotrebbe essere definito altrove come un tipo di dati. (Sembra che genererebbe una diagnostica del compilatore, ma chiaramente qualcosa di strano sta succedendo qui.) E come un altro test, si putch(0x61)comporta male allo stesso modo diputch('a') ? Mi chiedo se l'istruzione di lettura della tabella legga i dati a 8 o 16 bit. Il registro PIC W ha solo 8 bit, giusto?
MarkU

2
@MarkU, quindi ho provato un PIC16F1778 e lì la stessa cosa funziona bene. (il che lo rende un problema molto meno grave per me dato che sto bene con entrambi i chip, ma sarei comunque interessato a sapere come far funzionare il 18F27K40 ..)

Risposte:


3

Il tuo programma va bene, è un bug sul PIC18F27K40.

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

Usa il compilatore XC8 V1.41 e mplabx IDE, seleziona Opzioni globali XC8 / Linker XC8 e seleziona "Opzioni aggiuntive", quindi aggiungi +nvmregnella casella Errata e tutto andrà bene.

Estratto dal documento collegato, parole chiave contrassegnate in grassetto:

TBLRD richiede il valore NVMREG per puntare alla memoria appropriata

Le revisioni al silicio interessate dei dispositivi PIC18FXXK40 impropriamente richiedono l'impostazione dei NVMREG<1:0>bit nel NVMCONregistro per l' TBLRDaccesso alle varie aree di memoria. Il problema è più evidente nei programmi C compilati quando l'utente definisce un tipo const e il compilatore utilizza le TBLRDistruzioni per recuperare i dati dalla memoria flash del programma (PFM). Il problema è evidente anche quando l'utente definisce un array nella RAM per il quale il compilatore crea un codice di avvio, eseguito in precedenza main(), che utilizza le TBLRDistruzioni per inizializzare la RAM da PFM.


2

i caratteri const sono memorizzati nella memoria del programma (flash) e sembra che il compilatore stia vedendo che non lo stai usando come una variabile (poiché non cambia mai) e che lo ottimizzi nella memoria del programma indipendentemente dal fatto che tu usi const o no.

Prova a dichiararlo come volatile char c= 'a';. Questo costringerà ad essere archiviato in SRAM anziché in flash.

Perché è importante?

Sui PIC18, l'uso della direttiva db (databyte per memorizzare un byte nella memoria del programma) con un numero dispari di byte (come nel tuo caso) lo riempirà automaticamente di zeri. Questo comportamento differisce da quello del PIC16, motivo per cui funziona su uno ma non sull'altro. Per questo motivo, anche stringhe o caratteri archiviati nella memoria flash non funzioneranno con nessuna delle funzioni di stringa standard, come strcpy o printf. La memorizzazione di qualcosa nella memoria del programma non è automaticamente sicura.

Sulla base dell'assembly, è abbastanza chiaro che sta caricando gli 8 byte sbagliati. Che è 0x00, quindi invia correttamente 0x00 (come hai ampiamente confermato che sta facendo).

Al giorno d'oggi può essere difficile prevedere cosa otterrai con la folle quantità di ottimizzazione del compilatore, quindi non sono sicuro che funzionerà. il trucco volatile dovrebbe funzionare, ma se lo vuoi davvero archiviare in flash, prova questo:

TXREG = data & 0xff;

o forse

TXREG = data & 0x0ff;

So che in teoria questo non dovrebbe fare nulla. Ma stiamo provando a cambiare l'output dell'assembly del compilatore per fare ciò che vogliamo, e non un po ', ma non quello che vogliamo.

Dalla guida per l'utente di MPASM:

inserisci qui la descrizione dell'immagine

Consiglio anche di provarlo tu stesso , così come code_pack, nel PDF. Pagina 65

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.