Drukowanie znaków zmiennych do UART nie działa, stałe działają poprawnie

9

Mam dość dziwny problem z XC8 na mikrokontrolerze PIC18F27K40. Na PIC16F1778 działa . Zdefiniowałem:

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

Kiedy w mojej mainpętli dzwonię uart_putch('a');, działa to dobrze. Jednak gdy definiuję const char c = 'a';i dzwonię uart_putch(c);, to nie działa. Drukuje coś, choć nie jest a- myślę, że to 0x00postacie, z których czerpię hexdump -x /dev/ttyUSB0. To nie jest problem z portem szeregowym na moim komputerze; Patrzyłem z lunetą i sygnał jest inny (lewa działa, prawa nie):

wprowadź opis zdjęcia tutaj

Kod jest prosty:

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

To, co nie działa, to użycie dowolnej funkcji łańcuchowej ( puts, printfitp.), Co moim zdaniem jest powiązane - dlatego w tym pytaniu podałem minimalny działający przykład ze znakami.

Wygenerowany zespół, gdy używam zmiennej, cma:

_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

I ze stałą ma w _mainbloku:

    movlw   (061h)&0ffh 
    call    _putch

Używam kompilatora MPLAB XC8 C V1.41 (24 stycznia 2017 r.) Z obsługą części w wersji 1.41.

Odpowiednie części mojego 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 $<

Jakakolwiek pomoc w uzyskaniu tego działania byłaby bardzo mile widziana.


źródło
1
Zdefiniuj swój uart_putch jako „uart_putch (const char & c)”. Nazywa się to „przekazywaniem przez odniesienie”.
Rohat Kılıç
1
@ RohatKılıç To jest C ++
TisteAndii
1
@ tcrosley Chciałem to załączyć, przepraszam. To nie robi różnicy (wciąż nie działa). Próbowałem wszystko unsigned char, char, const unsigned chari const char.
1
Co stanie się w twojej definicji putch (), jeśli byteTxzamiast tego zmienisz nazwę argumentu ? Obawiam się, że bytemoże być zdefiniowany gdzie indziej jako typ danych. (Wygląda na to, że wygenerowałoby to diagnostykę kompilatora, ale najwyraźniej dzieje się tutaj coś dziwnego.) A jako kolejny test, czy putch(0x61)zachowuje się w ten sam sposób jak putch('a')? Zastanawiam się, czy instrukcja odczytu tabeli odczytuje dane 8-bitowe czy 16-bitowe. Rejestr PIC W ma jednak tylko 8 bitów, prawda?
MarkU
2
@ MarkU, więc wypróbowałem PIC16F1778 i tam to samo działa dobrze. (co sprawia, że ​​jest to dla mnie znacznie mniejszy problem, ponieważ nie mam nic przeciwko jednemu układowi, ale nadal chciałbym wiedzieć, jak uruchomić 18F27K40 do pracy ..)

Odpowiedzi:

3

Twój program jest w porządku, to błąd w PIC18F27K40.

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

Użyj kompilatora XC8 V1.41 i mplabx IDE, wybierz XC8 Global options / XC8 linker i wybierz „Dodatkowe opcje”, a następnie dodaj +nvmregw polu Errata i wszystko będzie dobrze.

Fragment połączonego dokumentu, słowa kluczowe oznaczone pogrubioną czcionką:

TBLRD wymaga wartości NVMREG, aby wskazać odpowiednią pamięć

Poprawione krzemowe wersje urządzeń PIC18FXXK40 nieprawidłowo wymagają NVMREG<1:0> bitów w NVMCONrejestrze w celu uzyskania TBLRDdostępu do różnych obszarów pamięci. Problem jest najbardziej widoczny w skompilowanych programach C, gdy użytkownik definiuje typ const, a kompilator używa TBLRDinstrukcji do pobierania danych z pamięci Flash programu (PFM). Problem jest również widoczny, gdy użytkownik zdefiniuje tablicę w pamięci RAM, dla której kompilator utworzy wcześniej uruchamiany kod main(), który korzysta z TBLRDinstrukcji inicjowania pamięci RAM z PFM.

Ian Munro
źródło
2

const znaki są przechowywane w pamięci programu (flash) i wygląda na to, że kompilator widzi, że nie używasz go jako zmiennej (ponieważ nigdy się nie zmienia) i optymalizuje go w pamięci programu, niezależnie od tego, czy używasz const, czy nie.

Spróbuj zadeklarować jako volatile char c= 'a';. Wymusi to zapisanie go w pamięci SRAM zamiast w pamięci flash.

Dlaczego to ma znaczenie?

W przypadku PIC18s użycie dyrektywy db (bajt danych do przechowywania bajtu w pamięci programu) z nieparzystą liczbą bajtów (jak w twoim przypadku) spowoduje automatyczne uzupełnienie go zerami. To zachowanie różni się od PIC16 i prawdopodobnie dlatego działa na jednym, ale nie na drugim. Z tego powodu ciągi znaków lub znaki przechowywane w pamięci flash również nie będą działać z żadnymi standardowymi funkcjami ciągów, takimi jak strcpy lub printf. Przechowywanie czegoś w pamięci programu nie jest automatycznie bezpieczne.

W oparciu o zestaw jest całkiem jasne, że ładuje niewłaściwe 8 bajtów. To jest 0x00, więc poprawnie wysyła 0x00 (jak dokładnie potwierdziłeś, że robi).

W dzisiejszych czasach może być trudno przewidzieć, co dostaniesz przy szalonej ilości optymalizacji kompilatora, więc nie jestem pewien, czy to zadziała. lotna sztuczka powinna działać, ale jeśli naprawdę chcesz, aby była przechowywana we flashu, spróbuj tego:

TXREG = data & 0xff;

lub ewentualnie

TXREG = data & 0x0ff;

Wiem, że teoretycznie nie powinno to nic robić. Ale staramy się zmienić dane wyjściowe asemblera kompilatora, aby robiły to, co chcemy, a nie w pewnym sensie, ale nie tak naprawdę, co chcemy.

Z Przewodnika użytkownika MPASM:

wprowadź opis zdjęcia tutaj

Polecam również samemu to sprawdzić , a także kod_pakietu w pliku PDF. Str. 65.

metakollina
źródło