Das Drucken variabler Zeichen in UART funktioniert nicht, Konstanten funktionieren einwandfrei

9

Ich habe ein ziemlich seltsames Problem mit XC8 auf einem PIC18F27K40-Mikrocontroller. Auf einem PIC16F1778 funktioniert es . Ich habe definiert:

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

Wenn ich in meiner mainSchleife anrufe uart_putch('a');, funktioniert dies einwandfrei. Wenn ich jedoch definiere const char c = 'a';und aufrufe uart_putch(c);, funktioniert es nicht. Es druckt etwas, wenn auch nicht a- ich denke, es sind 0x00Charaktere, von denen ich komme hexdump -x /dev/ttyUSB0. Dies ist kein Problem mit der seriellen Schnittstelle meines Computers. Ich habe mit einem Zielfernrohr gesucht und das Signal ist anders (links funktioniert, rechts nicht):

Geben Sie hier die Bildbeschreibung ein

Der Code ist einfach:

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

Was entweder nicht funktioniert ist eine der String - Funktionen verwenden ( puts, printfusw.), die ich denke , ist in Verbindung stehend - so in dieser Frage habe ich ein minimales Arbeits Beispiel mit Zeichen.

Die generierte Assembly, wenn ich eine Variable verwende, chat:

_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

Und mit einer Konstante hat es im _mainBlock:

    movlw   (061h)&0ffh 
    call    _putch

Ich verwende MPLAB XC8 C Compiler V1.41 (24. Januar 2017) mit Teilunterstützungsversion 1.41.

Die relevanten Teile meines Makefiles:

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 $<

Jede Hilfe, um dies zum Laufen zu bringen, wäre sehr dankbar.


quelle
1
Definieren Sie Ihre uart_putch als "uart_putch (const char & c)". Dies wird als "Referenzübergabe" bezeichnet.
Rohat Kılıç
1
@ RohatKılıç Das ist C ++
TisteAndii
1
@tcrosley Ich wollte das einschließen, sorry. Es macht keinen Unterschied (funktioniert immer noch nicht). Ich habe versucht , alles unsigned char, char, const unsigned charund const char.
1
Was passiert in Ihrer Definition von putch (), wenn Sie byteTxstattdessen das Argument umbenennen ? Ich mache mir Sorgen, dass bytedies an anderer Stelle als Datentyp definiert werden könnte. (Scheint so, als würde dies eine Compiler-Diagnose generieren, aber hier passiert eindeutig etwas Seltsames.) Und verhält sich ein anderer Test putch(0x61)genauso schlecht wie putch('a')? Ich frage mich, ob der Tabellenlesebefehl 8-Bit- oder 16-Bit-Daten liest. Das PIC W-Register ist allerdings nur 8 Bit, oder?
MarkU
2
@ MarkU also habe ich einen PIC16F1778 anprobiert und dort funktioniert das gleiche gut. (was es für mich zu einem viel weniger schlimmen Problem macht, da ich mit beiden Chips in Ordnung bin, aber ich wäre trotzdem interessiert zu wissen, wie ich den 18F27K40 zum Laufen bringen kann.)

Antworten:

3

Ihr Programm ist in Ordnung. Es ist ein Fehler auf dem PIC18F27K40.

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

Verwenden Sie den XC8-Compiler V1.41 und die mplabx-IDE, wählen Sie XC8 Global Options / XC8 Linker und wählen Sie "Additional options". Fügen Sie dann +nvmregdas Feld Errata hinzu, und alles wird in Ordnung sein.

Auszug aus dem verknüpften Dokument, fett markierte Schlüsselwörter:

TBLRD erfordert einen NVMREG-Wert, um auf den entsprechenden Speicher zu verweisen

Die betroffenen Siliziumrevisionen der PIC18FXXK40-Geräte erfordern zu Unrecht, dass die NVMREG<1:0>Bits im NVMCONRegister für den TBLRDZugriff auf die verschiedenen Speicherbereiche gesetzt sind. Das Problem tritt am deutlichsten in kompilierten C-Programmen auf, wenn der Benutzer einen Konstantentyp definiert und der Compiler TBLRDAnweisungen verwendet , um die Daten aus dem Programm-Flash-Speicher (PFM) abzurufen. Das Problem tritt auch auf, wenn der Benutzer ein Array im RAM definiert, für das der Complier einen zuvor ausgeführten Startcode erstellt main(), der TBLRDAnweisungen zum Initialisieren des RAM aus dem PFM verwendet.

Ian Munro
quelle
2

const-Zeichen werden im Programmspeicher (Flash) gespeichert, und es sieht so aus, als würde der Compiler feststellen, dass Sie sie nicht als Variable verwenden (da sie sich nie ändert) und sie im Programmspeicher optimieren, unabhängig davon, ob Sie const verwenden oder nicht.

Versuchen Sie es als zu deklarieren volatile char c= 'a';. Dadurch wird erzwungen, dass er im SRAM und nicht im Flash gespeichert wird.

Warum ist das wichtig?

Bei PIC18s wird die Verwendung der db-Direktive (Databyte zum Speichern eines Bytes im Programmspeicher) mit einer ungeraden Anzahl von Bytes (wie in Ihrem Fall) automatisch mit Nullen aufgefüllt. Dieses Verhalten unterscheidet sich von dem des PIC16, weshalb es wahrscheinlich auf dem einen, aber nicht auf dem anderen funktioniert. Aus diesem Grund funktionieren im Flash-Speicher gespeicherte Zeichenfolgen oder Zeichen auch nicht mit den Standardfunktionen für Zeichenfolgen wie strcpy oder printf. Das Speichern von etwas im Programmspeicher ist nicht automatisch typsicher.

Basierend auf der Assembly ist es ziemlich klar, dass die falschen 8 Bytes geladen werden. Welches ist 0x00, also sendet es korrekt 0x00 (wie Sie gründlich bestätigt haben, dass es funktioniert).

Es kann schwierig sein, vorherzusagen, was Sie heutzutage mit der wahnsinnigen Menge an Compiler-Optimierung erreichen werden, daher bin ich mir nicht sicher, ob dies funktionieren wird. Der flüchtige Trick sollte funktionieren, aber wenn Sie wirklich möchten, dass er in Flash gespeichert wird, versuchen Sie Folgendes:

TXREG = data & 0xff;

oder möglicherweise

TXREG = data & 0x0ff;

Ich weiß, dass dies theoretisch nichts bewirken sollte. Wir versuchen jedoch, die Assembly-Ausgabe des Compilers so zu ändern, dass sie das tut, was wir wollen, und nicht irgendwie, aber nicht wirklich das, was wir wollen.

Aus dem MPASM-Benutzerhandbuch:

Geben Sie hier die Bildbeschreibung ein

Ich empfehle auch , es selbst sowie code_pack im PDF zu überprüfen. Seite 65.

Metacollin
quelle