Печать переменных символов в 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)". Это называется «передача по ссылке».
Рохат
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в поле «Ошибки», и все будет хорошо.

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

TBLRD требует значение NVMREG для указания на соответствующую память

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

Ян Мунро
источник
2

константные символы хранятся в памяти программы (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.

metacollin
источник