I am trying to bit banging an UART Port using PIC32MX with timer5 (the only available at this time) but I am struggling how to configure the timer for a Baud Rate of 115200bps. I don't want a flow control not even to deal with parity bit. If possible can someone explain me on a Step-by-step procedure?

My Definitions are:

    #define GetSystemClock()            48000000UL              // System clock frequency (Hz)
    #define GetPeripheralClock()        48000000UL              // Peripheral clock frequency
    #define GetInstructionClock()       (GetSystemClock())      // Instruction clock frequency

    #define MILLISECONDS_PER_TICK       10                  // Definition for use with a tick timer
    #define TIMER_PRESCALER             TIMER_PRESCALER_8   // Definition for use with a tick timer
    #define TIMER_PERIOD                37500               // Definition for use with a tick timer

    #define SYS_FREQ                    40000000UL

    #pragma config FPLLMUL = MUL_20    // PLL Multiplier
    #pragma config FPLLIDIV = DIV_1 // PLL Input Divider
    #pragma config FNOSC = FRC // Oscillator Selection
    #pragma config POSCMOD = EC // Primary Oscillator
    #pragma config FPLLODIV = DIV_2 // PLL Output Divider
    #pragma config FPBDIV = DIV_1 // Peripheral Clock divisor
    #pragma config FWDTEN = OFF // Watchdog Timer (controlled by software)
    #pragma config WDTPS = PS65536 // Watchdog Timer Postscale 1048s
    #pragma config FCKSM = CSECMD // Clock Switching Enable & Fail Safe Clock Monitor Disable
    #pragma config OSCIOFNC = OFF // CLKO Disable
    #pragma config IESO = ON // Internal/External Switch-over
    #pragma config FSOSCEN = ON // Secondary Oscillator (KLO was off)

    void initTIMER5( void ){ // Initialize Timer 5

    T5CON = 0x0;   
    TMR5 = 0; 

    T5CONbits.TCKPS = 0b111;//1:256 prescale value

    IFS0bits.T5IF = 0;
    IPC2bits.T2IS = 0; 
    IPC2bits.T5IP = 2;
    IEC0bits.T5IE = 1;

    T5CONSET = 0x8000;

By now I think I just need to configure the T5CONbits.TCKPS and the PR5 register in order to synchronize with the baud rate, right?

enter image description here

I really need your help on this guys.

  • \$\begingroup\$ Are you transmitting only or receiving as well? \$\endgroup\$ – vini_i Jan 19 '16 at 17:08
  • \$\begingroup\$ I want to transmit and receive. To transmit I have to establish a baud rate with a Timer and to receive I will implement an ChangeNoticeHandler interrupt. \$\endgroup\$ – scuba Jan 19 '16 at 17:26
  • \$\begingroup\$ Don't use interrupt on change, you're asking for problems. \$\endgroup\$ – vini_i Jan 19 '16 at 17:29
  • \$\begingroup\$ The proper name is Change Notice (CN4 pin). \$\endgroup\$ – scuba Jan 19 '16 at 17:31
  • \$\begingroup\$ @vini_i Why do you recommend not to use Change Notification? \$\endgroup\$ – tcrosley Jan 19 '16 at 17:49

For both sending and receiving, you need to set up a timer interrupt.

One bit time for 115,200 baud is:

$${1,000,000 \over 115,200} = 8.68\space µs$$

If you are running with a peripheral clock of 48 MHz, then this corresponds to a period of 20.8 ns, or 0.0208 µs:

$${1,000,000 \over 48,000,000} = 0.0208\space µs$$

The number of counts for the timer is then:

$${8.68 \over 0.0208} = 417$$

So transmitting is easy, just set up a counter, and on each interrupt output the start bit, followed by 8 data bits, followed by a stop bit which lasts two timer intervals.

Receiving is a little trickier. To catch the falling edge of the RX lead, indicating the beginning of the start bit, you could use an Change Notification as you mentioned in a comment. Or, if you have an interrupt pin (INTx) unused, you could use that instead.

When the Change Notification interrupt comes in, you then want to reset your set your timer for one half the period, i.e. 4.34 µs, or 208 counts. Then, when the timer interrupt comes in, you should be in the middle of the start bit. If it has gone back high, then this was just noise. Otherwise change the timer back to one bit time (8.68 µs), and on each timer interrupt you will be sampling the middle of each data bit.

Ideally, you would like to scan each bit more than once. So if you set your initial timer after the Change Notification interrupt for 3.34 µs (160 counts) instead of 4.34 µs, you will be sampling the middle of the start bit minus one µs. Then wait 1 µs and sample again (you are now in the middle), and then once more (1 µs past the middle). You now have three samples to look at, so you can take the majority value. Wait 6.68 µs (321 counts) this time and repeat for each data bit.

Hardware UART's typically sample 16 times for each bit time.

You might want to get the simpler version working first (scanning just once in the middle).


I don't believe your setup is correct. The second line of your listing assumes your peripheral clock is 48 MHz, but looking at your clock setup, I think you are only running at 8 MHz.

Without an external crystal, the only way to get above frequencies of 8 MHz is to use the PLL. However you have the oscillator selection set to just FRC, which uses the internal 8 MHz oscillator directly. To get 48 MHz, you would need something like the following settings:

#pragma config FPLLMUL = MUL_24    // PLL Multiplier
#pragma config FPLLIDIV = DIV_2    // PLL Input Divider
#pragma config FNOSC = FRCPLL      // Oscillator Selection
#pragma config POSCMOD = OFF       // No Primary Oscillator
#pragma config FPLLODIV = DIV_2    // PLL Output Divider
#pragma config FPBDIV = DIV_1      // Peripheral Clock divisor
#pragma config IESO = OFF          // No Internal/External Switch-over

In Figure 8-1, page 141 of the datasheet, it says Fin must between 4 and 5 MHz. That means you must divide the internal RC clock by 2 (FPLLIDIV). Then you multiply it by 24 (FPLLMUL) and divide it by 2 (FPLLODIV) to get 48 MHz.

I don't know what the SYS_FREQ #define is being used for. Seems it should match GetSystemClock.

You didn't say which PIC32MX processor you are using. If it is one in the PIC32MX575/675/695/775/795 family, the internal FRC clock is only accurate to ±2% (Table 31-19, page 376). This may not be good enough for doing bit-banged UART at 115,200 baud -- generally baud rates need to be within 1.5%. You really should be using a 8 MHz crystal (with the clock settings updated once again) instead of the internal FRC clock.

  • \$\begingroup\$ Is there any problem to use 2 stop bits instead of one? So, to transmit 11 bits it will take 95,48 us (11bits*8.68us) which it means I need to count 4590,38 times (95,48 / 0,0208us) For this case I will set my PR5 = 11EE. For receiving I will try to do my code base on your tip. \$\endgroup\$ – scuba Jan 19 '16 at 18:34
  • 1
    \$\begingroup\$ For transmitting, you also want to interrupt every bit time (8.68 µs), not once for each character (95.5 µs), since you have to change the output line (TX) for each data bit depending on its value. And remember, the output is "upside down", you set the line high for a 0, and low for a 1 in the character being transmitted. \$\endgroup\$ – tcrosley Jan 19 '16 at 18:36
  • \$\begingroup\$ I am not achieving the 0.0208 µs period so It seems the 48Mhz does not correspond to the actual speed of the peripherals. There must be a delay somewhere but I am not able to found. I was looking at the diagram block and there is no divider. This is some other's person code/schematic. \$\endgroup\$ – scuba Jan 22 '16 at 12:45
  • 1
    \$\begingroup\$ @scuba I just looked over your system clock setup, which I had assumed was correct, since your original question was how to configure Timer5, and not how to configure the system clock. But I think you are probably only running at 8 MHz. See the EDIT in my answer. \$\endgroup\$ – tcrosley Jan 22 '16 at 14:42
  • \$\begingroup\$ This code was not written by me so its a bit confusing to understand it. But now with your explanation it seems quite clear that I am only running at 8Mhz. I can not modify the configs otherwise I will have a big problem to solve with the other timers. thanks again. \$\endgroup\$ – scuba Jan 22 '16 at 14:56

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.