La impresión de caracteres variables en UART no funciona, las constantes funcionan bien

9

Tengo un problema bastante extraño con XC8 en un microcontrolador PIC18F27K40. En un PIC16F1778 funciona . He definido:

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

Cuando, en mi mainbucle, llamo uart_putch('a');, esto funciona bien. Sin embargo, cuando defino const char c = 'a';y llamo uart_putch(c);, no funciona. Imprime algo, aunque no un a- Creo que son 0x00personajes, de los cuales obtengo hexdump -x /dev/ttyUSB0. Esto no es un problema con el puerto serie en mi computadora; Miré con un alcance y la señal es diferente (la izquierda funciona, la derecha no):

ingrese la descripción de la imagen aquí

El código es simple:

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

Lo que no funciona bien es el uso de cualquiera de las funciones de cadena ( puts, printf, etc.), que creo que está relacionado - por lo que en esta pregunta que hice un ejemplo básico mínimo, con los personajes.

El ensamblado generado cuando uso una variable ctiene:

_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

Y con una constante que tiene en el _mainbloque:

    movlw   (061h)&0ffh 
    call    _putch

Estoy usando MPLAB XC8 C Compiler V1.41 (24 de enero de 2017), con la versión de soporte parcial 1.41.

Las partes relevantes de mi 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 $<

Cualquier ayuda para que esto funcione será muy apreciada.


fuente
1
Defina su uart_putch como "uart_putch (const char & c)". Esto se llama "pasar por referencia".
Rohat Kılıç
1
@ RohatKılıç Eso es C ++
TisteAndii
1
@tcrosley Quería incluir eso, lo siento. No hace la diferencia (todavía no funciona). He intentado todo unsigned char, char, const unsigned chary const char.
1
En su definición de putch (), ¿qué sucede si cambia el nombre del argumento byteTx? Me preocupa que bytepueda definirse en otro lugar como un tipo de datos. (Parece que eso generaría un diagnóstico del compilador, pero claramente algo extraño está sucediendo aquí.) Y como otra prueba, ¿se putch(0x61)comporta mal de la misma manera que putch('a')? Me pregunto si la instrucción de lectura de tabla está leyendo datos de 8 bits o de 16 bits. El registro PIC W solo tiene 8 bits, ¿verdad?
MarkU
2
@MarkU, así que probé un PIC16F1778 y allí funciona lo mismo. (lo que hace que sea un problema mucho menos malo para mí, ya que estoy bien con cualquiera de los chips, pero aún así me interesaría saber cómo hacer que el 18F27K40 funcione ...)

Respuestas:

3

Su programa está bien, es un error en el PIC18F27K40.

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

Utilice el compilador XC8 V1.41 y mplabx IDE, seleccione Opciones globales XC8 / XC8 linker y seleccione "Opciones adicionales", luego agregue +nvmregen el cuadro Errata y todo estará bien.

Extracto del documento vinculado, palabras clave marcadas en negrita:

TBLRD requiere el valor NVMREG para apuntar a la memoria apropiada

Las revisiones de silicio afectadas de los dispositivos PIC18FXXK40 requieren incorrectamente que los NVMREG<1:0>bits en el NVMCONregistro se establezcan para TBLRDacceder a las diversas regiones de memoria. El problema es más evidente en los programas C compilados cuando el usuario define un tipo constante y el compilador usa TBLRDinstrucciones para recuperar los datos de la memoria Flash del programa (PFM). El problema también es evidente cuando el usuario define una matriz en RAM para la cual el compilador crea un código de inicio, ejecutado antes main(), que usa TBLRDinstrucciones para inicializar la RAM desde PFM.

Ian Munro
fuente
2

los caracteres const se almacenan en la memoria del programa (flash), y parece que el compilador está viendo que no lo está utilizando como una variable (ya que nunca cambia) y optimizándolo en la memoria del programa, independientemente de si usa const o no.

Intenta declararlo como volatile char c= 'a';. Esto obligará a que se almacene en SRAM en lugar de flash.

¿Por qué importa esto?

En PIC18s, el uso de la directiva db (databyte para almacenar un byte en la memoria del programa) con un número impar de bytes (como en su caso) lo rellenará automáticamente con ceros. Este comportamiento difiere del del PIC16, lo que probablemente sea la razón por la que funciona en uno pero no en el otro. Por esta razón, las cadenas o caracteres almacenados en la memoria flash tampoco funcionarán con ninguna de las funciones de cadena estándar, como strcpy o printf. Almacenar algo en la memoria del programa no es automáticamente seguro.

Según el ensamblaje, está bastante claro que está cargando los 8 bytes incorrectos. Que es 0x00, por lo que envía correctamente 0x00 (como has confirmado a fondo que lo está haciendo).

Puede ser difícil predecir lo que obtendrá con la increíble cantidad de optimización del compilador en estos días, por lo que no estoy seguro de si esto funcionará. el truco volátil debería funcionar, pero si realmente quieres que esté almacenado en flash, prueba esto:

TXREG = data & 0xff;

o posiblemente

TXREG = data & 0x0ff;

Sé que, en teoría, esto no debería hacer nada. Pero estamos tratando de cambiar la salida del ensamblador del compilador para hacer lo que queremos, y no lo que realmente queremos.

De la Guía del usuario de MPASM:

ingrese la descripción de la imagen aquí

También recomiendo revisarlo usted mismo , así como code_pack, en el PDF. Página 65.

metacollin
fuente