У меня довольно странная проблема с 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 $<
Любая помощь в получении этой работы будет очень признательна.
Ваша программа в порядке, это ошибка на 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, когда пользователь определяет константный тип , а компилятор используетTBLRD
инструкции для извлечения данных из программной флэш-памяти (PFM). Проблема также очевидна, когда пользователь определяет массив в ОЗУ, для которого компилятор создает код запуска, выполняемый доmain()
, который используетTBLRD
инструкции для инициализации ОЗУ из PFM.
константные символы хранятся в памяти программы (флэш-памяти), и похоже, что компилятор видит, что вы не используете их как переменную (поскольку она никогда не меняется) и оптимизирует ее в памяти программы независимо от того, используете ли вы константу или нет.
Попробуйте объявить его как volatile char c= 'a';
. Это заставит его хранить в SRAM, а не во флэш-памяти.
Почему это важно?
На PIC18 использование директивы db (байт данных для хранения байта в памяти программы) с нечетным количеством байтов (как в вашем случае) автоматически дополняет его нулями. Это поведение отличается от поведения PIC16, возможно, поэтому оно работает на одном, но не на другом. По этой причине строки или символы, хранящиеся во флэш-памяти, также не будут работать ни с одной из стандартных функций обработки строк, таких как strcpy или printf. Сохранение чего-либо в памяти программ не является автоматически безопасным по типу.
Судя по сборке, довольно ясно, что загружаются неправильные 8 байтов. Это 0x00, поэтому он правильно отправляет 0x00 (как вы полностью подтвердили).
Может быть трудно предсказать, что вы получите с безумным количеством оптимизации компилятора в наши дни, поэтому я не уверен, что это сработает. трюк с volatile должен работать, но если вы действительно хотите сохранить его во флэш-памяти, попробуйте следующее:
TXREG = data & 0xff;
или, возможно,
TXREG = data & 0x0ff;
Я знаю, что теоретически это ничего не должно делать. Но мы пытаемся изменить ассемблерный вывод компилятора, чтобы он делал то, что мы хотим, а не что-то вроде, но не совсем то, что мы хотим.
Из руководства пользователя MPASM:
Также рекомендую ознакомиться с ним самостоятельно , а также с code_pack в PDF. Страница 65.
ткросли
Рохат Кылыч
СореDakeNoKoto
пользователь17592
unsigned char
,char
и .const unsigned char
const char
пользователь17592
void putch(char data)
на самом деле является подписью, которую вы должны использовать для переопределения поведения stdout (см. Руководство пользователя MLAB XC8, 3.5.7).МаркУ
byteTx
В вашем определении putch(), что произойдет, если вместо этого вы переименуете аргумент ? Я обеспокоен тем, что этоbyte
может быть определено в другом месте как тип данных. (Кажется, это вызовет диагностику компилятора, но здесь явно происходит что-то странное.) И в качестве еще одного теста, ведет лиputch(0x61)
себя так же, какputch('a')
? Мне интересно, читает ли инструкция чтения таблицы 8-битные или 16-битные данные. Регистр PIC W всего 8 бит, верно?пользователь17592
byteTx
кроме того, что это имя изменено и в сборке. Использование0x61
вместо'a'
(в присваивании переменной илиputch
вызове) не имеет никакого значения. Сегодня днем, вернувшись домой, я попытаюсь запустить тот же код на совершенно другом процессоре, чтобы посмотреть, работает ли он там, и сравнить сборку, если она работает.домен
_main
, так как она отсутствуетcall _putch
.пользователь17592
xc8 --pass1
а затем связывает все вместе с помощью простого вызоваxc8
.Джон
пользователь17592
пользователь17592