Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Pic24fj64ga006 to PC UART communication issue

Status
Not open for further replies.

user19

Junior Member level 2
Junior Member level 2
Joined
Apr 7, 2017
Messages
22
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
209
Hi ,

I am trying to communicate between PIC24FJ64GA006 and PC using UART at baudrate 9600 .

But after programming the PIC and connecting the PIC and PC with UART to USB converter , the terminal is showing junk values repeatedly.

Is it related to the settings done in the PIC or with how the value is transmitted in the code ?

Please help me with the issue .

Please find the code below


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
 * File:   uart1.c
 * Author: User2
 *
 * Created on April 10, 2017, 11:21 AM
 */
 
 
#include "xc.h"
 
 #include "p24fj64ga006.h"
 
 _CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx1) 
 _CONFIG2(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMOD_HS & FNOSC_PRIPLL)
  
 
 #define FCY 8000000
  #define BAUDRATE 9600
  #define BRGVAL ((FCY/BAUDRATE)/16)-1
  unsigned int i;
 
 void InitClock() {
   // PLLFBD = 78;    // M = 160
    CLKDIV = 0x0043;
    //CLKDIVbits.PLLPOST = 1;    // N2 = 4
    //CLKDIVbits.PLLPRE = 3;    // N1 = 5
 
    while(OSCCONbits.LOCK != 1) {};
 }
 
 void Init_UART(void)
 {
        // configure U2MODE
    U1MODEbits.UARTEN = 0;  // Bit15 TX, RX DISABLED, ENABLE at end of func
    U1MODEbits.USIDL = 0;   // Bit13 Continue in Idle
    U1MODEbits.IREN = 0;    // Bit12 No IR translation
    U1MODEbits.RTSMD = 1;   // Bit11 Simplex Mode
    U1MODEbits.UEN = 0;     // Bits8,9 TX,RX enabled, CTS,RTS not
    U1MODEbits.WAKE = 0;    // Bit7 No Wake up (since we don't sleep here)
    U1MODEbits.LPBACK = 0;  // Bit6 No Loop Back
    U1MODEbits.ABAUD = 0;   // Bit5 No Autobaud (would require sending '55')
    U1MODEbits.RXINV = 0;   // Bit4 IdleState = 1
    U1MODEbits.BRGH = 0;    // Bit3 16 clocks per bit period
    U1MODEbits.PDSEL = 0;   // Bits1,2 8bit, No Parity
    U1MODEbits.STSEL = 0;   // Bit0 One Stop Bit
    
    U1BRG = BRGVAL; // baud rate
 
    // Load all values in for U1STA SFR
    U1STAbits.UTXISEL1 = 0; //Bit15 Int when Char is transferred (1/2 config!)
    U1STAbits.UTXINV = 0;   //Bit14 N/A, IRDA config
    U1STAbits.UTXISEL0 = 0; //Bit13 Other half of Bit15
    U1STAbits.UTXBRK = 0;   //Bit11 Disabled
    U1STAbits.UTXEN = 0;    //Bit10 TX pins controlled by periph
    U1STAbits.UTXBF = 0;    //Bit9 *Read Only Bit*
    U1STAbits.TRMT = 0;     //Bit8 *Read Only bit*
    U1STAbits.URXISEL = 0;  //Bits6,7 Int. on character recieved
    U1STAbits.ADDEN = 0;    //Bit5 Address Detect Disabled
    U1STAbits.RIDLE = 0;    //Bit4 *Read Only Bit*
    U1STAbits.PERR = 0;     //Bit3 *Read Only Bit*
    U1STAbits.FERR = 0;     //Bit2 *Read Only Bit*
    U1STAbits.OERR = 0;     //Bit1 *Read Only Bit*
    U1STAbits.URXDA = 0;    //Bit0 *Read Only Bit*
 
    IFS0bits.U1TXIF = 0;    // Clear the Transmit Interrupt Flag
    IEC0bits.U1TXIE = 1;    // Enable Transmit Interrupts
    IFS0bits.U1RXIF = 0;    // Clear the Recieve Interrupt Flag
    IEC0bits.U1RXIE = 1;    // Enable Recieve Interrupts
 
    U1MODEbits.UARTEN = 1;  // And turn the peripheral on
 
    U1STAbits.UTXEN = 1;
    /* wait at least 104 usec (1/9600) before sending first char */
    for(i = 0; i < 4160; i++)
    {
    Nop();
    }
    U1TXREG = 'a'; // Transmit one character
 }
 
 void __attribute__((__interrupt__)) _U1TXInterrupt(void)
 {
 IFS0bits.U1TXIF = 0; // clear TX interrupt flag
 U1TXREG = 'a'; // Transmit one character
 
 }
 
 int main(void)
 {
    InitClock();    
 
    //char message[] = "Bienvenue au lab";
 
    //Initialisation UART
    Init_UART();
    
    
 
    while(1)
    {
        //LATAbits.LATA0 = !LATAbits.LATA0;
        //Delay_1ms(500);
    }
 
 }

 
Last edited by a moderator:

obvious question: do you have your communication parameters set correctly on your pc? The fact that you're getting some data would indicate that this is the problem. Just as a sanity check, can you turn off the pic UART and verify that data stops coming to the pc (i.e., there's not something that's interfering with your comm port.) ? Can you look at your signals with an oscilloscope?
 

it's usually a sign a bad crystal frequency setting. Are you sure that your timings are valid? Is a 1000 ms delay in code really a 1000 ms delay in real world? Try checking it with blinking the LED....
 

Remove the include for the processor - the xc.h include will do that for you.
Your clock setup does not really make much sense. You are using HS mode for the primary oscillator which requires a crystal in the 10MHz to 32MHz range. You also use the PLL but that requires an input of 4MHz to 8MHz and has a maximum output frequency of 32MHz.
You don't mention the crystal frequency but either the crystal is not begin driven correctly (if it is lower than 10MHz) or you are overclocking the PLL.
You also use 8MHz (the #define of FCY) as the Fosc value to calculate the baud rate. This means that the baud rate calculation will not be correct.
(Also I hope you realise that defining the FCY symbol only impacts the built-in '_delayxxx' macros and any calculations you make that includes the symbol - it has absolutely no impact on the configuration of the MCU.)
This is the most likely reason you are getting bad characters on the PC - UARTs normally need to be within 1% or 2% to be reliable and my guess is that you are way out with the oscillator setup.
Not that it affects your code, but you also set the CLKDIV register to 0x43 - in other words you try to set the bottom 8 bits of the register. For that device, the bottom 8 bits of the CLKDIV register are unused so that instruction does nothing. However it does make me think that you have simply copied the code from some other device without looking at the differences between the it and the one you are using.
Finally, you have obviously never received a character from the PC as you have set the U1RXIE bit but not provided the corresponding ISR (at least you have no shown it if you have). When the UART receives a character it will trigger the ISR but the address at the interrupt vector location will cause the processor to go to address 0 which is jump to the reset code. Basically, as soon as you receive a character then device will reset on you. The basic lesson is that you never set an IE bit for anything without writing the corresponding ISR.
You have set up the Tx ISR correctly so that it will send a character. I suggest that you read step #3 in Section 17.2 of the data sheet and you will see that enabling the TX side of the UART will automatically trigger an interrupt - this is by design so you can create a completely interrupt driven Tx capacity. THat alkso measn that you don't need to send a character as part of the 'Init_UART' function. It does not hurt to do so - and it would be instructive for you to send a character other than the one being sent by the ISR so that you can see the order the characters are actually sent - but is unnecessary here.
Susan
 
Hi Susan,

Could you please suggest the method to get the desired baud rate for 8 MHz Internal Oscillator with 4x PLL Option ?

Thanks
 

The first step is to get the oscillator working correctly. Look at Table 8-1 in the data sheet and you will see that the configuration of using the FRC (the 8MHz internal oscillator) and the PLL requires that you set the POSCMOD to 0b11 and FNOSC to 0b001. Both of these are set in the config registers so you need to look at Section 24 of the data sheet and in particular at the Register 24-2 definition.
If you look at the top of the register definition, you will see that the information about the FNOSCx bits is "R/PO-1". That means the bit is normally read-only and that it has a default value (i.e. when you completely initialise the device before programming) of 1. The 'PO' means that it can be programmed once (after each complete device initialisation) - normally the compiler will take care of that part when you use the "#pragma config" (or in your case you are using the older _CONFIG2 macro) statement.
You need FNOSC to be the FRCPLL bit combination so you will need to work out how to do that - going by your original code I'm guessing that will mean "FNOSC_PRIPLL" in the _CONFIG2 macro argument.
Netx look at the setting above the POSCMD bits in Register 24-2 and you will see that the default for these bits is also 1. (Actually the default for nearly all config register bits is 1 but there are exceptions so you need to check.) As the POSCMD bit value you want is 0b11 you can leave this setting alone and it will be right.
All that will do is make sure that the device will power up correctly after it is programmed. Next you need to go back to to Section 8 and look at Figure 8-1. There you will see that there is a prescalar controlled by specific bits in the CLKDIV register between the FRC and the PLL. The PLL takes as input a frequency between 4MHZ and 8MHz and you have said you want to use the 8MHZ option. Therefore you need to set that prescalar to be 1:1. Look at the CLKDIV register definition (Register 8-2) and you will see that the bits you want are called RCDIV. Looking at the legend above those bits you will see that the power-on-reset values are 0 for the top two bits and 1 for the bottom bit. If you look at the meaning of that bit combination you will see that it is is 'divide-by-2'. Therefore you need to set the bits to 0b000 which is 'divide-by-1'. You need to do that in your code - something like "CLKDICbits.RCDIV = 0" or whatever your compiler syntax is.
Of course you need to consider the accuracy of the FRC. According to Table 27-20 in the data sheet, the FRC has an accuracy of +/-2% which (in my opinion) is borderline for the UART. HOwever sa the clock is 32MHz and you wil be dividing that down for 9600 BAUD for the UART it wil probably be OK. If not then you can use the OSCTUN register to make some adjustments.
Once the oscillator is working at the specified frequency then you can calculate the required UxBRG register value. You already have the formula for that assuming the other settings or the UART remain the same.
This might look like a lot of work but it takes far longer to describe it than to actually do it. Getting the oscillator configuration right is a critical first step in any project and not much else will work correctly if you don't do it correctly.
Susan
 
  • Like
Reactions: user19

    user19

    Points: 2
    Helpful Answer Positive Rating
Hi Susan,

I tried the following settings.

Changed _CONFIG2( FNOSC_PRIPLL) to _CONFIG2( FNOSC_FRCPLL)

Added CLKDIVbits.RCDIV =0

Tried with the POSCMOD values with XT and NONE.

But we are getting the following screenshot .

Please find the attached screenshot. https://obrazki.elektroda.pl/4830664900_1492061552.png


Thanks
 

In the USB to UART converter have you selected voltage level to 3.3V. There should be a switch or jumper to set the voltage level.
 

Hi Okada,

Yes we have selected voltage level to 3.3V.

Thanks
 

Is your Oscillator configured properly ?
 

Hi Okada,

Please find the PIC settings below


Code:
 _CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx1) 
 _CONFIG2(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMOD_XT & FNOSC_FRCPLL)
  
 
 #define FCY 8000000
  #define BAUDRATE 9600
  #define BRGVAL ((FCY/BAUDRATE)/16)-1
       //  #define BRGVAL 0x1A0
  unsigned int i;
 
 void InitClock() {
    //PLLFBD = 78;    // M = 160
    //CLKDIV = 0x0043;
     CLKDIVbits.RCDIV0=0;
     CLKDIVbits.RCDIV1=0;
    CLKDIVbits.RCDIV2=0;
    //CLKDIVbits.PLLPOST = 1;    // N2 = 4
    //CLKDIVbits.PLLPRE = 3;    // N1 = 5
 
    while(OSCCONbits.LOCK != 1) {};
 }
 
 void Init_UART(void)
 {
	U1MODEbits.UARTEN = 0;	// Bit15 TX, RX DISABLED, ENABLE at end of func
	U1MODEbits.USIDL = 0;	// Bit13 Continue in Idle
	U1MODEbits.IREN = 0;	// Bit12 No IR translation
	U1MODEbits.RTSMD = 1;	// Bit11 Simplex Mode
	U1MODEbits.UEN = 0;		// Bits8,9 TX,RX enabled, CTS,RTS not
	U1MODEbits.WAKE = 0;	// Bit7 No Wake up (since we don't sleep here)
	U1MODEbits.LPBACK = 0;	// Bit6 No Loop Back
	U1MODEbits.ABAUD = 0;	// Bit5 No Autobaud (would require sending '55')
	U1MODEbits.RXINV = 0;	// Bit4 IdleState = 1
	U1MODEbits.BRGH = 0;	// Bit3 16 clocks per bit period
	U1MODEbits.PDSEL = 0;	// Bits1,2 8bit, No Parity
	U1MODEbits.STSEL = 0;	// Bit0 One Stop Bit
	
	//U1BRG = BAUDRATEREG1;	// baud rate
    U1BRG = BRGVAL;
	// Load all values in for U1STA SFR
	U1STAbits.UTXISEL1 = 0;	//Bit15 Int when Char is transferred (1/2 config!)
	U1STAbits.UTXINV = 0;	//Bit14 N/A, IRDA config
	U1STAbits.UTXISEL0 = 0;	//Bit13 Other half of Bit15
	U1STAbits.UTXBRK = 0;	//Bit11 Disabled
	U1STAbits.UTXEN = 0;	//Bit10 TX pins controlled by periph
	U1STAbits.UTXBF = 0;	//Bit9 *Read Only Bit*
	U1STAbits.TRMT = 0;		//Bit8 *Read Only bit*
	U1STAbits.URXISEL = 0;	//Bits6,7 Int. on character recieved
	U1STAbits.ADDEN = 0;	//Bit5 Address Detect Disabled
	U1STAbits.RIDLE = 0;	//Bit4 *Read Only Bit*
	U1STAbits.PERR = 0;		//Bit3 *Read Only Bit*
	U1STAbits.FERR = 0;		//Bit2 *Read Only Bit*
	U1STAbits.OERR = 0;		//Bit1 *Read Only Bit*
	U1STAbits.URXDA = 0;	//Bit0 *Read Only Bit*

	IFS0bits.U1TXIF = 0;	// Clear the Transmit Interrupt Flag
	IEC0bits.U1TXIE = 1;	// Enable Transmit Interrupts
	IFS0bits.U1RXIF = 0;	// Clear the Recieve Interrupt Flag
	IEC0bits.U1RXIE = 1;	// Enable Recieve Interrupts

	U1MODEbits.UARTEN = 1;	// And turn the peripheral on

	U1STAbits.UTXEN = 1;

}

Thanks
 

You need to understand the questions you ask in the first place! In post #5 you asked how to set up the oscillator to use the FRC with the PLL and that is what I showed you how to do. The end result of that is that the oscillator will be running at 32MHz. That also means that Fosc will be 32MHz.
However you have still set the FCY preprocessor symbol to the equivalent of 8MHz - that means your baud rate calculations will be out by a factor of 4.
You can't guess values for the CONFIG settings as you seem to have done with the POSCMD setting. You said you want to use the FRC and that means there is only ONE setting of POSCMD and that is POSCMOD_NONE. I even suggested that you leave that setting out of the _CONFIG2 macro and it would be what you want.
I have no idea what you are showing with the picture to link to in post #7 as I can't see where the character being sent starts. I can only guess that you are still sending the 'a' character which is 0x61 and I can't relate the bit pattern to that value.
However I see that you are STILL enabling the Rx interrupt which will cause your processor to reset if you have not provided an Rx ISR.
By the way, you can make things a little easier for yourself by setting all of the RCDIV bits at the same time with code such as:
Code:
CLKDIVbits.RCDIV = 0;
Susan
(and my apologies for the spelling mistakes in my previous posts and any in this post - I'm definitely not a typist and sometimes the spelling checker does not pick up the bad spelling)
 

Hi Susan,

Apologies for the misunderstanding. We are connecting PIC to PC and now changed the value FCY=Fosc/2=16MHz and sending the character 'a' .Now getting the value 'a' in the serial terminal.


Thanks
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top