Uart bit banging code

Discussion in 'Embedded Systems and Microcontrollers' started by Vindhyachal Takniki, Apr 6, 2016.

  1. Vindhyachal Takniki

    Thread Starter Member

    Nov 3, 2014
    1. I have a application in which uart is done by software since it has only one uart & it is used for another purpose.
    MCU is 16Mhz with 62.5ns instruction time. Goal is to continuously receive data on software uart at 9600 baud & transmit it on hardware uart at 57600 baud.

    2. Below is code for above task. Delay I have made from timer to be as accurate as possible.

    3. Is there any way I can best optimize code for this task. One thing I am tryign to do is to move tranmit section on hardware uart in interrupt to have least possible time in main.

    4. Is this code ok for software uart?

    Code (Text):
    1. #define SYSTEM_FREQ_HZ   16000000
    2. #define BAUD_RATE        9600
    4. #define DELAY_US_1_5_BIT    ((16000000 / 9600) * 1.5)   //approx 2500us
    5. #define DELAY_US_1_0_BIT    ((16000000 / 9600) * 1.0)   //approx 1666.67us
    6. #define DELAY_US_0_5_BIT    ((16000000 / 9600) * 0.5)   //approx 833.33us
    8. void rx_byte(void)
    9. {
    10.     uint8_t data_val;
    11.     uint8_t cnt;
    12.     uint8_t err;
    14. /* pin as input pull up */
    15.     RX_PIN_INPUT_PULLUP();
    17.     while(1)
    18.     {
    19.         data_val = 0U;
    20.         err = 0U;
    22.     /* while pin is high */
    23.         while(1U == READ_PIN());
    25.     /* 1.5 bit delay */
    26.         delay(DELAY_US_1_5_BIT);
    28.     /* get byte */
    29.         for(cnt = 0U ; cnt < 8U ; cnt++)
    30.         {
    31.             if(1U == READ_PIN())
    32.             {
    33.                 data_val = data_val | (1U << cnt);
    34.             }
    36.             /* 1 bit delay */
    37.             delay(DELAY_US_1_0_BIT);        
    38.         }
    40.     /* stop bit error low */
    41.         if(0U == READ_PIN())
    42.         {
    43.             err = 1U;
    44.         }
    46.     /* 0.5 bit delay */
    47.         delay(DELAY_US_0_5_BIT);    
    49.     /* send byte on another uart */
    50.         if(0U == err)
    51.         {
    52.             uart_tx_data(data_val);
    53.         }
    54.     }
    55. }
  2. Papabravo


    Feb 24, 2006
    TRIGGER WARNING: Harsh comments ahead. Do not read this post if you are easily offended or have a sensitive nature, just continue to muddle on as you have been.
    1. Your bit timing numbers for 9600 bits per second communication are off by a considerable amount. What you receive from a device transmitting at 9600 baud will be garbage using those timing values. Try doing the calculation of a bit time one more time.
    2. Your code appears to assume that the format of the data will be 1 START bit, 8 data bits, and 1 STOP bit. Do you know for a fact that this will be the only data format you will use?
    3. 16 MHz. is not the optimum baudrate to be using for baudrates of 9600 and 57600. Why? Because those baudrates are not factors of the operating frequency. You need to have better than 2% accuracy in bit timing for reliable communication.
    4. It is a classic programming mistake to write any infinite loop that waits on a single condition. You always want to have a condition that breaks you out of an infinite loop so you can recover when things go wrong unexpectedly.
    Vindhyachal Takniki likes this.
  3. Vindhyachal Takniki

    Thread Starter Member

    Nov 3, 2014
    1. Ahhhh!. It is 9600 bps. So bit time should be (1000000us/9600)
    1.5 bit time in us = (1000000us/9600) * 1.5 = 156.25us
    1.0 bit time in us = (1000000us/9600) * 1.0 = 104.167us
    0.5 bit time in us = (1000000us/9600) * 0.5 = 52.083us

    2. Yes format is always 1 start,8data & 1 stop

    3. System freq is 16Mhz. When I use hardware uart with 57600 baud, error is around -0.080% as written in datasheet.
    Software uart may have issues.

    4. In code I am not doing anything else. Code waits for input byte at 9600 baud & then sends it at once.
  4. Picbuster


    Dec 2, 2013
  5. John P

    AAC Fanatic!

    Oct 14, 2008
    Delay functions are lazy programming. You should be using first a low-going edge interrupt, then timer interrupts for each bit. If there are other interrupts which can occur, this may fail, but not as badly as if you used those stupid delay() routines.

    I can't understand this sentence:
    "One thing I am tryign to do is to move tranmit section on hardware uart in interrupt to have least possible time in main."

    I don't see why transmitting via the hardware UART would ever involve an interrupt, or why it needs to be a function. On a PIC processor, it just requires you to write a byte to a particular register, and transmission happens. I assume other processors are pretty much the same.
    Robin Mitchell likes this.
  6. dannyf

    Well-Known Member

    Sep 13, 2015
    Code (Text):
    2. [LIST=1]
    3. [*]#define SYSTEM_FREQ_HZ   16000000
    4. [*]#define BAUD_RATE        9600
    5. [*]
    7. [*]#define DELAY_US_1_5_BIT    ((16000000 / 9600) * 1.5)   //approx 2500us
    8. [*]#define DELAY_US_1_0_BIT    ((16000000 / 9600) * 1.0)   //approx 1666.67us
    9. [*]#define DELAY_US_0_5_BIT    ((16000000 / 9600) * 0.5)   //approx 833.33us
    10. [*]
    since you already defined SYSTEM_FREQ_HZ AND BAUD_RATE, why would you hardwire them in those DELAY_USx macros?

    I would see 1) if you can run the Rx routine in the interrupt; and 2) if you can use the hardware uart for Rx and software uart for Tx: it is generally much harder to write a receiver / slave routine than a transmitter / maser routine.
  7. Vindhyachal Takniki

    Thread Starter Member

    Nov 3, 2014
    I have tried by making rx from 9600 baud uart by software & then when rx is complete send at once at tx of 115200 uart.
    I tested it but after few bytes code fails. Majorly after 2 bytes or there after. However if one byte is sent & delay b/w two bytes then codes fine.

    Meanwhile now some specs are changed. Now I have to do bidirectional uart. Let say uart1 is with 9600 baud & uart2 is with 115200 baud.
    Now data rx on uart1 is to be sent on uart2 & data rx on uart2 is to be sent on uart1.
    Maximum data size to be tx or rx is 250KB-500kB. (small video)

    Now i have selected a MCU with 2hardware uart.
    I will try by making two hardware uart, one with 9600 & other with 115200 baud. Each uart has interrupt for rx only. When data is rx on any uart, in ISR it will send it immediately to other uart inside ISR.

    But I dont think this will work without data buffer. How to calculate optimal buffer size for this application.
  8. MaxHeadRoom


    Jul 18, 2013
    If you have a MCU with UART module you could do it with one module and switch baud rates between RX & TX.
    Is this a PICmicro?
  9. dannyf

    Well-Known Member

    Sep 13, 2015
    You get to your goal faster by walking slowly and surely.
  10. John P

    AAC Fanatic!

    Oct 14, 2008
    You are correct about that. Suppose data just comes in continuously on the fast UART; how can you ever send it out equally fast on the slow UART? A buffer will save data until the slow UART can send it, but you need to know how much data has to be stored.

    Also, it is nearly impossible to write a software UART that can work in full duplex mode. That's where a character can start arriving while another is being transmitted. The only way to do it is to have a clock that interrupts the processor at 4x the baud rate, so you can check for incoming data. If you're writing code that involves delay() routines, this isn't going to work.
    Papabravo likes this.
  11. odm4286

    Active Member

    Sep 20, 2009
    You my friend, are incredibly dramatic. I'd never think I'd see so much emotion on a post about embedded programming. I think its YOU that is easily offended or agitated by questions that don't fit your approved format.

    OP, I still learning this stuff as well. Bit banging is essentially software emulated UART right?
  12. Papabravo


    Feb 24, 2006
    Fact is there are a number of sensitive people here, and yes I'm lampooning the tendency among American university students to require their professors to warn them of material that might upset them. In my view if you put your work out their for critical review you should be prepared to see actual suggestions for improvement. This view is not universally held however.

    BTW, the TS/OP liked what I said.
    Robin Mitchell likes this.
  13. odm4286

    Active Member

    Sep 20, 2009
    Putting your work up there is one thing, putting something you're learning is different. At the end of the day, why does it bother you that much? Just help if you're going to help, no need for the melodramatic disclaimer in bold to start your post.
    Last edited: Apr 9, 2016
  14. takao21203

    AAC Fanatic!

    Apr 28, 2012
    software async serial is a pain. You need a crystal. You need precize timing.
    sync serial is easy. Couldnt you use synchronous?

    Delays are even worse. Id try interrupts. And waiting for a condition in a loop is bad too. Some time I did but continously resetting the controller so if theres an error it only hangs for some milliseconds.

    Really controllers hanging up can be avoided completely but you see it all day in commercial products. They do wait for conditions in a loop.

    If I need another hardware device I add another small controller and do software sync port as the timing can be flexible very much.

    The problem really is to test the conditions with software. The receiver must know the sender will transmit, and the sender must know the receiver is ready. Its hard to have them ready all the time so you need flow control as well.

    So if you add a small controller with hardware port you can buffer it in RAM and transmit to master controller some time sync port can exceed 1 MBPS easily.
  15. NorthGuy

    Active Member

    Jun 28, 2014
    This will work for receiving on slow UART and sending to the fast one. However, this will not work for receiving on fast UART and sending to the slow one.

    You must have a buffer, and the size of the buffer depends on the amount of data you receive from the fast UART.
  16. John P

    AAC Fanatic!

    Oct 14, 2008
    He said "Maximum data size to be tx or rx is 250KB-500kB. (small video)". Therefore I am extremely dubious about any kind of buffering.

    Of course there is always interactive data transmission with start and stop commands, but personally I would not want to go there.
  17. Papabravo


    Feb 24, 2006
    Since you seem more obsessed on this than the TS/OP, maybe you should follow you're own advice and just let it go. Las time I checked I didn't notice that you were a moderator.
  18. NorthGuy

    Active Member

    Jun 28, 2014
    500KB/s would require 5MBaud. 9600 (or 115200 for that matter) is hopelessly slow.
  19. MrChips


    Oct 2, 2009
    VT, Save yourself a headache and get a microcontroller with multiple UARTS. There are plenty available.
  20. John P

    AAC Fanatic!

    Oct 14, 2008
    Actually there aren't many PIC processors in the mid-range series that have two UARTs, and those that there are, all have 64 pins. I've sometimes thought that the best way to deal with this could be just to get 2 PICs and link them via SPI. But however you do it, if the UART speeds are mismatched, there can be a necessity to buffer data that comes in on the fast port, while it waits for the slow port. How about a serial RAM chip, as made by various vendors including Microchip?

    I see that there are some new PIC processors coming along that will have as few as 8 pins but 2 UARTs. That sounds like a highly specialized item!
    Last edited: Apr 10, 2016