0
\$\begingroup\$

I'm trying to use the printf family of functions in C18 for a PIC18F26J50. In my system, the output should go through the UART and show up in RealTerm. Here is my approach:

  1. I initialized CPU clock, UART and GPIO before doing anything else. The main test code is a very simple one:
VOID main( VOID )
{
    char s[STR_SIZE];    
    memset( s, 0x00, sizeof(s) );

    strcpypgm2ram(s, "1234567890\n0987654321");

    clockInit();
    uartInit(BAUD_115200);
    ledAliveInit();

    fprintf( _H_USER, "%s", s );

    while( 1 );
}
  1. I initialize and use the UART as follows (please, note that I implemented the _user_putc function as required by the library):
#include <p18cxxx.h>

#define UART_READ       0
#define UART_WRITE      1

PRIVATE UINT32 speed_[] = {19200, 38400, 57600, 115200};

/*----------------------------------------------------------------------------*/

PRIVATE UINT16_VAL getBrgValue_( const UINT8 baud )
{
    UINT16_VAL value;

    value.Val = (UINT16)((CLOCK/(4*speed_[baud])) - 1);

    return value;
}

/*----------------------------------------------------------------------------*/
PRIVATE VOID uartEnableWrite_( VOID )
{   
    LATAbits.LATA2 = UART_WRITE;    
}

/*----------------------------------------------------------------------------*/
PRIVATE VOID uartEnableRead_( VOID )
{
    LATAbits.LATA2 = UART_READ;
}

/*----------------------------------------------------------------------------*/

VOID uartInit( const UINT8 baudRate )
{
    if( (baudRate >= 0) && (baudRate <= 3) )
    {

        UINT16_VAL brgValue;

        // disables analog-to-digital conversion pins
        // (enables digital IO on all AD pins)
        ANCON0              = 0x1F;
        ANCON1              = 0x1F;   
        ADCON0bits.VCFG1    = 0;    
        CM1CONbits.CON      = 0;         // disables comparator  

        //Configuration TX and RX pins
        TRISCbits.TRISC6 = DIGITAL_OUTPUT;
        TRISCbits.TRISC7 = DIGITAL_INPUT; 

        // baud rate setup
        BAUDCON1bits.ABDEN  = 0;    // disable auto-baud    
        BAUDCON1bits.BRG16  = 1;    // enable 16bit register for baud rate generator
        BAUDCON1bits.WUE    = 0;    // disable wake-up bit

        // baud rate calculation and loading
        brgValue    = getBrgValue_(BAUD_115200);

        SPBRG1      = brgValue.byte.LB;
        SPBRGH1     = brgValue.byte.HB;   

        // TX setup
        TXSTA1bits.TX9      = 0;        // don't transmit 9th bit
        TXSTA1bits.SYNC     = 0;        // ASYNC mode
        TXSTA1bits.BRGH     = 1;        // high speed communication
        TXSTA1bits.SENDB    = 0;        // don't send 12-bit BREAK char

        RCSTA1bits.RX9      = 0;        // 8-bit reception
        RCSTA1bits.CREN     = 1;        // enables receiver

        // enables rs485 transceiver direction control
        TRISAbits.TRISA2    = DIGITAL_OUTPUT;

        RCSTA1bits.SPEN     = 1;        // enable serial port
        TXSTA1bits.TXEN     = 1;        // enable TX
    }
}

/*----------------------------------------------------------------------------*/

PRIVATE VOID uartSendByteInternal_( const UINT8 b )
{
    while (!TXSTA1bits.TRMT); 
    TXREG1 = b;   
}

/*----------------------------------------------------------------------------*/

INT8 uartSendByte( const UINT8 b )
{
    INT8 rc = ERROR_SUCCESS;

    uartEnableWrite_(); 
    uartSendByteInternal_( b );
    uartEnableRead_();

    return rc;
}

/*----------------------------------------------------------------------------*/

VOID uartDeInit( VOID )
{
    PIE1bits.RCIE   = 0;
    PIE1bits.TXIE   = 0;
    RCSTA1bits.SREN = 0;
    RCSTA1bits.CREN = 0;
    RCSTA1bits.SPEN = 0;
    TXSTA1bits.TXEN = 0;       
}

/*----------------------------------------------------------------------------*/
int _user_putc (char c)
{
    (VOID)uartSendByte( (UINT8)c );
    return c;
}
  1. When I run this code I get the following in RealTerm: printf

If I change the string, the result changes. I can't find the problem but my guess is that it is related to different "types" of memory (rom x ram) from the PIC being used incorrectly.

\$\endgroup\$
  • \$\begingroup\$ does it work at 9600 baud? \$\endgroup\$ – Marcus Müller Jun 15 '19 at 5:57
  • \$\begingroup\$ Did you even modify SPBRG directly? \$\endgroup\$ – jonk Jun 15 '19 at 6:12
  • \$\begingroup\$ No, it does not work at 9600bps. Yes, I did tried modifying SPBRG directly (I took some sample values from this page: nicksoft.info/el/calc/?ac=spbrg). I assumed that even in high speed modes, I could use slower baud rates but I'm not sure. \$\endgroup\$ – daniel.franzini Jun 18 '19 at 14:15
0
\$\begingroup\$

Looks like a baudrate mismatch, you don't show your clockInit() function so it's not easy to say. Maybe you can check with a scope to make sure your baudrate is correct.

And two more comments:

-Hardware: You don't mention anything about the serial port on your Windows PC. If you're using a USB-to-RS232 cable make sure it takes 3.3V logic. If it's TTL instead you need to add pull-up resistances on your RX and TX lines and activate the open-drain mode, according to the datasheet:

enter image description here

-Software: C18 is not my cup of tea, but I've used this minimum UART example written in XC8 from the Microchip forums with minor modifications:

#include <xc.h>
#include <stdint.h>
#include <stdbool.h>

#define _XTAL_FREQ 48000000UL

#define RS485_READ 1
#define RS485_WRITE 0
#define IOF_8MHz 0b111
#pragma config XINST = OFF 

void clockInit(void);
uint8_t high8(uint16_t x);
uint8_t low8(uint16_t x);

void main(void) {

    clockInit();

    // disables analog-to-digital conversion
    // (enables digital IO on all AD pins)
    ANCON0 = 0x1F;
    ANCON1 = 0x1F;

    // enables rs485 write (output)
    TRISAbits.TRISA2 = 0;

    TXSTA1bits.SYNC = 0;
    TXSTA1bits.BRGH = 1; // set BRGH bit
    TXSTA1bits.TXEN = 1; // enable TX

    RCSTA1bits.SPEN = 1;
    RCSTA1bits.CREN = 1;

    TRISCbits.TRISC6 = 0;
    TRISCbits.TRISC7 = 1; // Rx1 set input

    BAUDCON1bits.BRG16 = 1; // set 16 bits SPBRG
    BAUDCON1bits.RCIDL = 1; // set receive active

    SPBRGH1 = high8(104); // set UART speed SPBRGH
    SPBRG1 = low8(104); // set UART speed SPBRGL 

    CM1CONbits.CON = 0; // disables comparator


    /* Loop forever */
    while (1) {
        LATAbits.LATA2 = RS485_WRITE;

        TXREG1 = 0x55; // yes, send char 
        while (!TXSTA1bits.TRMT); // Ready ?

        LATAbits.LATA2 = RS485_READ;
        __delay_us(100);
    }
}

/*----------------------------------------------------------------------------*/
void clockInit(void) {
    // disables reference oscillator output
    REFOCONbits.ROON = 0;

    // device enters IDLE mode on SLEEP instruction
    OSCCONbits.IDLEN = 1;
    // system clock is from primary oscillator
    OSCCONbits.SCS = 0;
    // selects base frequency as 8MHz
    OSCCONbits.IRCF = IOF_8MHz;
    // wait until oscillator is running
    while (!OSCCONbits.OSTS);

    // low speed USB (6MHz clock)
    UCFGbits.FSEN = 0;

    // enable PLL
    OSCTUNEbits.PLLEN = 1;
}

uint8_t high8(uint16_t x) {
    return (uint8_t) (x >> 8);
}

uint8_t low8(uint16_t x) {
    return (uint8_t) (x & 0xFF);
}
\$\endgroup\$
  • \$\begingroup\$ This code is from a post I wrote to the Microchip forums. I'm glad it is being used elsewhere. \$\endgroup\$ – daniel.franzini Jun 19 '19 at 22:09
  • \$\begingroup\$ Well, that's a coincidence... I wonder why you went for C18 then. Have you tried this code for your current problem? What about the pull-up resistors? \$\endgroup\$ – Marcos G. Jun 20 '19 at 3:35
  • \$\begingroup\$ The original code I wrote was also for C18. Some guy ported it to xc8 and returned to me but at that time the problem was related with clock and I figured it out using the xc8 code and other answers as well. I use C18 because that is what I have avaliable and because I think xc8 is too expensive (avr-gcc is just free). Amazes me the fact we don't have production quality C compiler for PIC18. \$\endgroup\$ – daniel.franzini Jun 21 '19 at 14:21
  • \$\begingroup\$ No wonder PIC lost the lead they had back in the old days of ASM. I was never professionally involved with PIC and when I had I used CSC. These days I use XC8 free, is it really that bad with the free version compared to the paid license? I mean code optimization. On PIC16 I never had any issues. But I agree with you, the available of good tools is very important. \$\endgroup\$ – Marcos G. Jun 21 '19 at 14:47
  • \$\begingroup\$ I meant free tools, of course. I haven't tested xc8 free yet but reports say it is very very bad. \$\endgroup\$ – daniel.franzini Jun 21 '19 at 18:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.