1
\$\begingroup\$

I am trying to setup a PIC24FJ64GB002 for UART communication in MBLAB using XC16. I am using the USB CDC demo to communicate with a device, and I am trying to relay that information to an arduino using the PIC. I am confused as to what frequency the cpu is running at. I am using an external 8 MHZ crystal, with several bits set in the demo. Bits relating to the oscillator are set here.

#include <p24FJ64GB002.h>
#include "system.h"
#include "usb.h"

/** CONFIGURATION Bits **********************************************/
_CONFIG1(
    WDTPS_PS1 &
    FWPSA_PR32 &
    WINDIS_OFF &
    FWDTEN_OFF &
    ICS_PGx1 &
    GWRP_OFF &
    GCP_OFF &
    JTAGEN_OFF
)

_CONFIG2(
    POSCMOD_HS &
    I2C1SEL_PRI &
    IOL1WAY_OFF &
    OSCIOFNC_ON &
    FCKSM_CSDCMD &
    FNOSC_PRIPLL &
    PLL96MHZ_ON &
    PLLDIV_DIV2 &
    IESO_OFF
)

_CONFIG3(
    WPFP_WPFP0 &
    SOSCSEL_SOSC &
    WUTSEL_LEG &
    WPDIS_WPDIS &
    WPCFG_WPCFGDIS &
    WPEND_WPENDMEM
)

_CONFIG4(
    DSWDTPS_DSWDTPS3 &
    DSWDTOSC_LPRC &
    RTCOSC_SOSC &
    DSBOREN_OFF &
    DSWDTEN_OFF
)

/*********************************************************************
* Function: void SYSTEM_Initialize( SYSTEM_STATE state )
*
* Overview: Initializes the system.
*
* PreCondition: None
*
* Input:  SYSTEM_STATE - the state to initialize the system into
*
* Output: None
*
********************************************************************/
void SYSTEM_Initialize( SYSTEM_STATE state )
{
    //On the PIC24FJ64GB004 Family of USB microcontrollers, the PLL will not power up and be enabled
    //by default, even if a PLL enabled oscillator configuration is selected (such as HS+PLL).
    //This allows the device to power up at a lower initial operating frequency, which can be
    //advantageous when powered from a source which is not gauranteed to be adequate for 32MHz
    //operation.  On these devices, user firmware needs to manually set the CLKDIV<PLLEN> bit to
    //power up the PLL.
    {
        unsigned int pll_startup_counter = 600;
        CLKDIVbits.PLLEN = 1;
        while(pll_startup_counter--);
    }

    switch(state)
    {
        case SYSTEM_STATE_USB_HOST:
            PRINT_SetConfiguration(PRINT_CONFIGURATION_LCD);
            break;

        case SYSTEM_STATE_USB_HOST_CDC_BASIC:
            BUTTON_Enable(BUTTON_USB_HOST_CDC_BASIC);
            PRINT_SetConfiguration(PRINT_CONFIGURATION_LCD);
            break;
    }
}

I then use this function to initialize the UART

void UART_INIT()
{
   AD1PCFGL = 0xFFFF;
   __builtin_write_OSCCONL(OSCCON & 0xbf);
   TRISBbits.TRISB15 = 0;
   __builtin_write_OSCCONL(OSCCON | 0x40);
   RPOR7bits.RP15R = 3;
   U1BRG = 103; //set baud speed
   U1MODE   =   0x8000;  //turn on module
   U1STA    =   0x8400;  //set interrupts
   IEC0bits.U1TXIE = 0;
   IFS0bits.U1RXIF = 0;
   IFS0bits.U1TXIF = 0;
}

And this function to transmit a byte

void send(char c)
{
   while(U1STAbits.UTXBF == 1);
   U1TXREG = c;
}

I am trying to figure out what value FCY should be defined to be. I assumed that it would be 16 MHZ, (96MHz / 3) / 2 but the code did not work at that setting. Could there be another problem in the code?

I am making all pins digital and setting the UART pin as an input with this code

__builtin_write_OSCCONL(OSCCON & 0xbf);
AD1PCFGL = 0xFFFF;
TRISBbits.TRISB15 = 0;
UART_INIT(9600);
__builtin_write_OSCCONL(OSCCON | 0x40);

Finally, I use the functions like this

UART_INIT(9600); 

while(1) 
{ 
send('H'); 
send('e'); 
send('l'); 
send('l'); 
send('o'); 
send(' '); 
send('W'); 
send('o'); 
send('r'); 
send('l'); 
send('d'); 
send('\n'); 
} 
\$\endgroup\$
4
  • \$\begingroup\$ In your CONFIG2 you have FNOSC_PRIPLL selected. So your CPU is probably being clocked at 48MHz (if you haven't messed with the CPDIV bits in the CLKDIV register). \$\endgroup\$
    – brhans
    Feb 23, 2016 at 22:25
  • \$\begingroup\$ But PLLDIV_DIV2 is also set, so isn't the frequency really 24 MHZ, but I tried that and it didn't work. \$\endgroup\$ Feb 23, 2016 at 22:30
  • \$\begingroup\$ After Reading The Fine Manual in a little more detail (and paying particular attention to section 8.5), it seems that you're most likely to have a 32MHz CPU clock. The 96MHz PLL requires a 4MHz input (which is why you need PLLDIV_DIV2), and that gets divided by 3 before being fed to the CPU. \$\endgroup\$
    – brhans
    Feb 23, 2016 at 22:39
  • \$\begingroup\$ That would mean that the FCY = 32/2 = 16 MHZ except that i tried it and doesn't work. \$\endgroup\$ Feb 25, 2016 at 3:07

5 Answers 5

2
+50
\$\begingroup\$

A diagram would help convey what you're doing. I think this is what you have implemented:

"a device" (USB device) <-> USB <-> PIC24FJ64BG002 (USB host) <-> UART <-> Arduino

Let's take a look at the clock options for this part:

enter image description here

Let's also look more closely at the USB-specific clock stuff:

enter image description here

CONFIG2 contains your oscillator-related stuff:

_CONFIG2(
POSCMOD_HS &                      
I2C1SEL_PRI &
IOL1WAY_OFF &
OSCIOFNC_ON &
FCKSM_CSDCMD &
FNOSC_PRIPLL &
PLL96MHZ_ON &
PLLDIV_DIV2 &
IESO_OFF
)

Recapping what we know:

  • Your source crystal is 8 MHz (input from POSC)
  • POSCMOD is set to HS Oscillator Mode
  • FNOSC is set to Primary Oscillator + PLL
  • PLLDIV is set to divide-by-2

Also, from the datasheet:

  • The default setting for CPDIV is 0x00, which is divide-by-1 (32 MHz)

So, what's our conclusion? I would say that unless there's other code messing with the bits somewhere, the situation is as is shown in figure 8.2 - HSPLL is running at 32 MHz (96 MHz USB PLL output, divided by three, then divided by one).

And, because we know that

\$ F_{CY} = \dfrac {F_{OSC}}{2} \$

the answer should be 16 MHz.

Now, to your baud rate formula:

baud = (FCY/(16*baud))-1;

(It's bad practice to have the same variable name on both sides of the equation: the left side should be renamed to BRG or something more like what it is - it's the baud rate generator value, not the baud rate itself.)

If you look up the PIC24 Family Reference Manual for UART, you'll find the values pre-computed for you:

enter image description here enter image description here

By default, BRGH is zero so unless code is messing with it, your baud rate generator should be set to 103 decimal. (Your formula is for BRGH - 0 and with a 16 MHz clock rate agrees with this table.)

I would dare a guess and say that your UART issues, if they persist, aren't clock related...

\$\endgroup\$
3
  • \$\begingroup\$ I have the same problems, even when just plugging in 103 \$\endgroup\$ Mar 2, 2016 at 3:57
  • \$\begingroup\$ The problem was simple, I had forgotten to call the init method which turns on the PLL, but great answer. \$\endgroup\$ Mar 2, 2016 at 20:34
  • \$\begingroup\$ Bingo. At least you have it resolved now. \$\endgroup\$ Mar 2, 2016 at 20:36
1
\$\begingroup\$

In PIC24 core, FCY is half the oscillator frequency. With external 8 MHz crystal, multiplied by 4 (PLL), divided by 2 (PLLDIV), and then divided by 2 once again (first sentence) you'll get 8 MHz. Oscillator is also available at REFO pin, you can enable it and measure the frequency directly using counter, oscilloscope, or a logic analyzer.

\$\endgroup\$
1
  • \$\begingroup\$ I tried that but when running this code, gibberish comes out on the arduino UART_INIT(9600); while(1) { send('H'); send('e'); send('l'); send('l'); send('o'); send(' '); send('W'); send('o'); send('r'); send('l'); send('d'); send('\n'); } \$\endgroup\$ Feb 23, 2016 at 22:52
1
\$\begingroup\$

Other answers have greatly explained about configuration settings, my focus is on the code you are using for UART Communication. Microchip provides peripheral library functions which you can use directly in your program instead of putting values in registers. Go to c\Program Files\Microchip\(your compiler)\docs you will find many documentation for it or try searching for PIC18/PIC24/PIC32 peripheral library. I have not worked in PIC24 but the functions are same for all the MCU series like PIC18 PIC24 PIC32. For example, for UART:

OpenUART(): to initialize UART channel.
putsUART(): to send string to your UART
getsUART(): to receive string from UART
putcUART(): to send a char.
getcUART(): to receive a char

you can use these functions directly and save your time.!

Demo Code:

/*
*
*/
int main()
{
  /*
  *
  */
  OpenUART1( UART_EN | UART_NO_PAR_8BIT | UART_1STOPBIT, UART_RX_ENABLE | UART_TX_ENABLE, (FPB/16/BAUDRATE)-1 );
  while(1)
  {
    putsUART1("Hello World");
  }
}
\$\endgroup\$
2
  • \$\begingroup\$ What header needs to be included to use those functions \$\endgroup\$ Mar 2, 2016 at 20:10
  • \$\begingroup\$ @popgalop To use peripheral library, you need to include plib.h \$\endgroup\$
    – Aircraft
    Mar 3, 2016 at 10:38
0
\$\begingroup\$

if you are unsure if your clock is working perfectly just toggle a pin using __delay_us(x) and see if the output waveform on the oscilloscope is right.

and regarding the baud rate the equation has a single mistake (compiler stupidity) , try this : baud = (FCY/(16.0*baud))-1 . when you add ".0" to 16 , you are forcing a float divide , because sometimes the compiler makes optimizations and the result of is not correct if integer is used. I faced exactly same issue before and this solved it.

hope that helps

\$\endgroup\$
0
\$\begingroup\$

Things to try:

  • Disable the transmit interrupt and clear TX interrupt flag
  • Calculate the U1BRG value yourself and enter it into the register.
  • Since you are unsure of the FCY value, try 4M, 8M, 16M, 32M ... until one works.

The code should look like this, rearranged a bit:

void UART_INIT()
{
   __builtin_write_OSCCONL(OSCCON & 0xbf);
   RPOR7bits.RP15R = 3;   // connect uart1 tx to RP15
   //AD1PCFGL = 0xFFFF;  //try the code with and without this line
   __builtin_write_OSCCONL(OSCCON | 0x40);
   U1BRG = 103;    //set baud value for 9600 (verify)
   IEC0bits.U1TXIE = 0;  //just in case
   IEC0bits.U1RXIE = 0;
   U1MODE   =   0x8000;  //turn on module
   U1STA    =   0x0400;  // enable TX
   IFS0bits.U1TXIF = 0;
   IFS0bits.U1RXIF = 0;
}

void send(char c)
{
   while(U1STAbits.UTXBF);
   U1TXREG = c;
}

void uart_print(const char * str){
    while (*str)
       send(*str++);
}

void main(){
    //initialize clock and other stuff here

    UART_INIT(); 
    //add a delay of 20ms here, just in case

    while(1)
       uart_print("Hello world\n");
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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