Друк змінних символів до UART не працює, константи працюють нормально


9

У мене досить дивна проблема з XC8 на мікроконтролері PIC18F27K40. На PIC16F1778 він працює . Я визначив:

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

Коли в своєму mainциклі дзвоню uart_putch('a');, це працює чудово. Однак коли я визначаю const char c = 'a';і дзвоню uart_putch(c);, це не працює. Це щось друкує, хоч і не a- я думаю, що вони є 0x00персонажами, з яких я берусь hexdump -x /dev/ttyUSB0. Це не проблема із послідовним портом на моєму комп’ютері; Я подивився з розмахом, і сигнал інший (ліворуч працює, право не робить):

введіть тут опис зображення

Код простий:

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

Те, що не працює, - це використання будь-якої з рядкових функцій ( puts, printfі т. Д.), Які, на мою думку, пов'язані - тому в цьому питанні я зробив мінімальний робочий приклад з символами.

Створена збірка, коли я використовую змінну, cмає:

_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

І з константою він має в _mainблоці:

    movlw   (061h)&0ffh 
    call    _putch

Я використовую MPLAB XC8 C Compiler V1.41 (24 січня 2017 р.), З частиною підтримкою версії 1.41.

Відповідні частини мого 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 $<

Буде дуже вдячна будь-яка допомога, щоб зробити цю роботу.


1
Визначте свій uart_putch як "uart_putch (const char & c)". Це називається "проходження посилання".
Rohat Kılıç

1
@ RohatKılıç Це C ++
TisteAndii

1
@tcrosley Я мав на увазі це включити, вибачте. Це не має значення (все ще не працює). Я спробував все unsigned char, char, const unsigned charі const char.

1
У вашому визначенні putch (), що станеться, якщо byteTxзамість цього перейменувати аргумент ? Мене хвилює, що в byteінших місцях можна визначити тип даних. (Здається, це створило б діагностику компілятора, але тут явно щось дивне відбувається.) І як інший тест, чи putch(0x61)неправильно поводиться так само, як putch('a')? Мені цікаво, чи інструкція з читання таблиці читає 8-бітні або 16-бітні дані. Регістр PIC W - це лише 8 біт, правда?
MarkU

2
@MarkU, тому я спробував на PIC16F1778 і там те саме працює добре. (що робить для мене набагато менш поганою проблемою, оскільки я добре з будь-яким чіпом, але все-таки мені було б цікаво знати, як змусити 18F27K40 працювати.)

Відповіді:


3

Ваша програма прекрасна, це помилка на PIC18F27K40.

Дивіться http://ww1.microchip.com/downloads/en/DeviceDoc/80000713A.pdf

Використовуйте XC8 компілятор V1.41 та mplabx IDE, виберіть пункт XC8 Global options / XC8 linker та виберіть "Додаткові параметри", потім додайте +nvmregу поле Errata і все буде добре.

Витяг із пов'язаного документа, ключові слова, позначені жирним шрифтом:

TBLRD вимагає значення NVMREG, щоб вказати на відповідну пам'ять

Поточні зміни кремнію пристроїв PIC18FXXK40 неправильно вимагають встановити NVMREG<1:0>біти в NVMCONрегістрі для TBLRDдоступу до різних областей пам'яті. Проблема найбільш очевидна у складених програмах C, коли користувач визначає тип const, а компілятор використовує TBLRDінструкції для отримання даних із флеш-пам’яті програми (PFM). Проблема також очевидна, коли користувач визначає масив в ОЗУ, для якого компілятор створює пусковий код, виконаний раніше main(), і використовує TBLRDінструкції для ініціалізації оперативної пам'яті з PFM.


2

символи const зберігаються у пам'яті програми (flash), і схоже, що компілятор бачить, що ви не використовуєте його як змінну (оскільки вона ніколи не змінюється) і оптимізує її в пам'яті програми незалежно від того, використовуєте ви const чи ні.

Спробуйте оголосити це як volatile char c= 'a';. Це змусить його зберігатись у SRAM, а не у спалаху.

Чому це має значення?

У PIC18, використання директиви db (байт даних для зберігання байтів у пам'яті програми) з непарною кількістю байтів (як у вашому випадку), автоматично додає нулі. Така поведінка відрізняється від поведінки PIC16, тому, ймовірно, тому вона працює на одній, а не на іншій. З цієї причини рядки або символи, що зберігаються у флеш-пам'яті, також не працюватимуть із будь-якою зі стандартних функцій рядків, наприклад strcpy або printf. Зберігання чогось у пам'яті програми не є автоматично безпечним.

Виходячи з збірки, досить зрозуміло, що завантажується неправильні 8 байт. Що означає 0x00, тож він правильно надсилає 0x00 (як ви ретельно підтвердили, що це робить).

Це може бути важко передбачити, що ви отримаєте з божевільної оптимізації компілятора в ці дні, тому я не впевнений, чи це спрацює. мінливий трюк повинен працювати, але якщо ви дійсно хочете, щоб він зберігався у спалах, спробуйте це:

TXREG = data & 0xff;

або, можливо,

TXREG = data & 0x0ff;

Я знаю, що теоретично це нічого не повинно робити. Але ми намагаємось змінити вихідний збірник компілятора на те, щоб робити те, що ми хочемо, а не на зразок, але не насправді того, що ми хочемо.

З посібника користувача MPASM:

введіть тут опис зображення

Я також рекомендую перевірити його самостійно , а також code_pack в PDF. Сторінка 65.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.