Because of the Thanksgiving holiday in the U.S., TI E2E™ design support forum responses may be delayed from November 25 through December 2. Thank you for your patience.

This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/MSP430g2553: Daisy Chaining Several SPI devices

Part Number: MSP430G2553

Tool/software: Code Composer Studio

Hi,

I want to control four daisy chained SPI slaves with the MSP430 (the master device). I have several issues doing this:

1. I want the SPI clk rate to be 16 MHz, the maximum clk frequency of my microcontroller. Here is what I do:

BCSCTL1  = CALBC1_16MHZ;                             	// Set range to 16MHz
DCOCTL   = CALDCO_16MHZ;                             	// Set DCO step and modulation to 16MHz

UCA0BR0 |= 0x01;					//baud rate
UCA0BR1 = 0;

When I set the clk rate to 16MHz, and observe the Din and SCLK signal generated by MSP430, it looks almost like a sine wave (the rise time is really slow). When I slow down the clk to 1 MHZ, the two signals look fine. I want to run the SPI clk at 16 MHz. How can I do that without compromising the signal integrity?

2. Each slave device has 8 switches, so for four devices, I need to send 32 bits to slave one. The bits should then travel through the shift registers to get to the last device.I do not know how to do this. I am sending 8 bits as follows:

P1OUT &= ~0x02;                                                                 //select device
if (IFG2 & UCA0TXIFG) 								//if USCI_A0 TX buffer ready
  {
     UCA0TXBUF = 0x2D; 								//send data over SPI to slave

  }

if (IFG2 & UCA0RXIFG); 							        // if USCI_A0 RX Received
  {
     received_ch = UCA0RXBUF; 							// Store received data
     P1OUT |= 0x02;								//unselect device, update switches
  }

Can anyone tell me how to do this? 

Here is the entire code for your reference: 

#include "msp430G2553.h"


volatile char received_ch = 0;
int main(void) {

	  WDTCTL   = (WDTPW | WDTHOLD);                       	// Stop watchdog timer

	  BCSCTL1  = CALBC1_16MHZ;                             	// Set range to 16MHz
	  DCOCTL   = CALDCO_16MHZ;                             	// Set DCO step and modulation to 16MHz

	  P1OUT    &= ~0x02;                           			// Chip select (P1.1)
	  P1DIR    |= 0x02;                                    	// Set the pins to output direction
	  P1SEL    = 0x14;                                   	// Set special function to timer module (P1.4-->Sclk, P1.2-->DIN)
	  P1SEL2   = 0x14;										//Universal serial communication
	  UCA0CTL1 = UCSWRST;									//put the module in reset mode to set up operations
	  UCA0CTL0 |= UCCKPH + UCMSB + UCMST + UCSYNC; 			//3-pin, 8-bit SPI master
	  UCA0CTL1 |= UCSSEL_2;									//SMCLK
	  UCA0BR0 |= 0x01;										//baud rate
	  UCA0BR1 = 0;
	  UCA0MCTL = 0; 										//no modulation, should be cleared when using SPI mode
	  UCA0CTL1 &= ~UCSWRST; 								//initialize USCI state machine

	  IE2 |= UCA0TXIE; 										//Enable USCI0 TX interrupt
	  _BIS_SR(GIE);                                  		// Enable global interrupts

	  while( 1 );                                         	// Endless loop
	}

#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{
	P1OUT &= ~0x02; 										//Sync not is active low. When low, DIN and shift registers are enabled, when high data is updated.

	if (IFG2 & UCA0TXIFG) 									//if USCI_A0 TX buffer ready
		{
		UCA0TXBUF = 0x2D; 									//send data over SPI to slave
		}

		if ((IFG2 & UCA0RXIFG)); 							// if USCI_A0 RX Received
		{
		received_ch = UCA0RXBUF; 							// Store received data

		P1OUT |= 0x02;										//unselect device, update switches
		}
 }


  • I'm having trouble visualizing your device(s). If it's 4x cascaded shift registers, then it's only one (SPI) device with a 32-bit "command" buffer, and you have to send a command to all your (sub)devices simultaneously. If it's 4x SPI devices, then there are 4x Chip Selects, and at any Select the other 3x devices are supposed to stay off the bus. Can you provide a part number?

    Specifically:
    1) "if ((IFG2 & UCA0RXIFG)); " Remove that semicolon. It's probably causing your transaction to be terminated mid-byte.
    2) Don't use interrupts at all. For SPI speed close to CPU speed, you're spending maybe 80% of your time with the SPI idle. It also complicates your life unnecessarily. Just write a little SPI_Tx() function and call it 4 times.
    3) I've run 3x SPI devices (EEPROMs) multidrop at full speed from a G2553, and the clock looked fine. Slow rise/fall times suggest bus contention (too-strong pullup maybe?).
  • re the second part of your query : start with Maxim's app note 3947 ( or similar document )  and see also, in particular,  Figure 16-2 of SLAU144J.

    Not all SPI devices such as port expanders or even "old style" SISO shift registers can be easily daisy-chained; choose your part(s) carefully.

    follow carefully the rules on controlling CS to the chained devices.

  • The part I am using is ADG714 from analog devices. I am using the implementation shown in figure 7 of the datasheet: www.analog.com/.../ADG714_715.pdf

    Thanks for the catch on the if statement. The issues still remain.

    Regarding not using interrupt loops: The problem is I have to use an interrupt loop because I have other tasks that need to get done by an ISR and the timing of the SPI commands are dependent on these tasks. For example, I will be reading from an ADC and when something is detected, one or multiple switches of ADG714 need to close.

    Regarding the pullup resistors: I am not actually connecting the microcontroller to the SPI devices. I plan to use 10k resistors. But right now, I am just looking at the output of the microcontroller on the pins generation Sclk, CS, and MOSI signals. Do you think that the rise time delay is because no device is actually connected?

    Thank you,
  • Hi Sahar!

    Sahar Elyahoodayan said:
    Do you think that the rise time delay is because no device is actually connected?

    No, definitely not - the edges will decrease with additional load capacitance, not vice versa.

    Are you using the G2 LaunchPad or a self-made board? On the LaunchPad, P1.2 is also connected to the UART<->USB converter via the jumper. You should disconnect it.

    You have the wrong SPI mode - the data is captured on the falling edge which is the second if the clock idles low. Furthermore you want to receive something and store it in a variable, but you did not enable the SOMI function.

    Anyway - for your purpose, I would do something like this (note that I use the RX interrupt to properly detect the last written byte before setting SYNC high again - this slows down the transmission a bit):

    #include "msp430g2553.h"
    #include "stdint.h"
    
    void adg714_start_transmission( void );
    
    volatile uint8_t adg714_bytes[4] = { 0x15, 0x25, 0x35, 0x45 }; // Random bytes for the ADG714 devices
    volatile uint8_t bytecounter;
    
    void main( void )
    {
      WDTCTL    = (WDTPW | WDTHOLD);            // Stop watchdog timer
      
      BCSCTL1   = CALBC1_16MHZ;                 // Set range to 16MHz
      DCOCTL    = CALDCO_16MHZ;                 // Set DCO step and modulation to 16MHz
    
      P1OUT     = 0x02;                         // SYNC at P1.1 high powers down ADG714 SCLK and DIN buffers
      P1DIR     = 0x02;                         // Set P1.1 to output direction
      
      P1SEL     = 0x14;                         // Set special function register 1 for UCA0SIMO (P1.2) and UCA0CLK (P1.4)
      P1SEL2    = 0x14;                         // Set special function register 2 for UCA0SIMO (P1.2) and UCA0CLK (P1.4)
      
      UCA0CTL1  = UCSWRST;                      // Set USCI module in reset state
      UCA0CTL0  = (UCMSB | UCMST | UCSYNC);     // Clock idles low, data changed on first and captured on second edge, MSB first, master, synchronous mode
      UCA0CTL1 |= UCSSEL_2;                     // SMCLK as clock source
      UCA0BR0   = 1;                            // Pre-scaler 1
      UCA0BR1   = 0;
      UCA0CTL1 &= ~UCSWRST;                     // Release USCI module from reset
      
      __bis_SR_register( GIE );                 // Enable global interrupts
      
      while( 1 )                                // Endless loop
      {
        // ...
    
        if( something_happened )                // Event trigger to send data
        {    
          adg714_start_transmission();          // Initiate transmission
        }
    
        // ...
      }
    }
    
    void adg714_start_transmission( void )
    {
      P1OUT       &= ~0x02;                     // SYNC low powers up ADG714 SCLK and DIN buffers
      IFG2        &= ~UCA0RXIFG;                // Clear pending RX interrupt flag
      IE2         |= UCA0RXIE;                  // Enable USCIA0 RX interrupt
      bytecounter  = 0;                         // Reset bytecounter
      UCA0TXBUF    = adg714_bytes[bytecounter]; // Transmit first byte
    }
    
    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR( void )
    {
      if( ++bytecounter < 4 )                   // Not all bytes sent yet
      {
        IFG2      &= ~UCA0RXIFG;                // Clear RX interrupt flag
        UCA0TXBUF  = adg714_bytes[bytecounter]; // Send next byte
      }
      else                                      // All bytes were sent
      {
        IE2   &= ~UCA0RXIE;                     // Disable USCIA0 RX interrupt
        P1OUT |= 0x02;                          // Update ADG714 outputs
      }
    }

    [Code not tested]

    Dennis

  • Hi Dennis,


    Thank you for answering my questions and the example code.


    Yes, I am using the G2 launchpad. As you suggested, I disconnected jumper 5 which connects UART to pin 1.2 and I ran the example code you provided. It works well at 1MHz, but it will start to lose signal integrity as before at higher clock frequencies. By that I mean the SCLK and DIN signals are no longer a sharp 3V or GRD. Rather, at any frequency higher than 1MHz, they will experience delay in rise/fall time and contain oscillations. The issue gets worse with higher frequencies. Do you know why?


    If I run the clock at 1MHz, 32 bits will take more than 160us to be transmitted to 4 slaves. This is a long delay for my purpose.


    Thank you,

  • But you're using a real oscilloscope for measuring the signals? Not one of those 1MHz bandwidth DIY kits like the DSO 062, for example? I will run the example on a LaunchPad in a few hours and post some screenshots for comparison.

    Dennis
  • So here you can see my measurements - it is always the first byte 0x15. Blue is SYNC, green is clock and purple is data.

    1MHz:

    8MHz:

    16MHz:

    Sure, the 16MHz clock isn't as nice as the one for 1MHz, but it is absolutely OK.

    Dennis

  • I see, so it is ok because the SPI devices will filter out the oscillations and do not care about the rise/fall time delay?

    Thanks a lot,
  • Sahar Elyahoodayan said:
    I see, so it is ok because the SPI devices will filter out the oscillations and do not care about the rise/fall time delay?

    It is all about threshold levels - normally inputs have Schmitt triggers that do not care much about slow rising / falling edges (but I wouldn't talk about slow here). If the oscillation would pass the threshold level you could get in trouble, but as long as it stays away from it, everything is fine - and this is the case here.

    I have a few more pictures for you - as I said, my example triggers on the RX IFG which wastes a bit of time compared to trigger on the TX IFG, but I don't know how fast you need the transmission to be. Here is the picture for the RX trigger from my example:

    This is about 12µs.

    You can see the gaps in between the data packets - if you change the code to trigger on the TX interrupt, the USCI state machine does not wait until the byte has been transmitted before it copies the next byte. Instead it would copy the next byte when the TX buffer is free and this happens while the previous byte is currently transmitted. But since your SPI is running at CPU frequency, you will not benefit as much as you would if the SPI would run at a lower frequency. Remember that entering the ISR also takes some CPU cycles. At CPU frequency this will be more than one byte time of the SPI.

    I often prefer to trigger on RX because you definitely know when the last byte has been transmitted and you can safely pull CS (or SYNC in this case) high again. But you can also work with the UCBUSY bit, of course.

    But I agree to Bruce - when having the SPI clock near to the CPU's clock frequency, interrupt driven might not give you a benefit. You could also think about doing something like this:

    #include "msp430g2553.h"
    #include "stdint.h"
    
    void adg714_start_transmission( void );
    
    uint8_t adg714_bytes[4] = { 0x15, 0x25, 0x35, 0x45 }; // Random bytes for the ADG714 devices
    
    void main( void )
    {
      WDTCTL    = (WDTPW | WDTHOLD);            // Stop watchdog timer
    
      BCSCTL1   = CALBC1_16MHZ;                 // Set range to 16MHz
      DCOCTL    = CALDCO_16MHZ;                 // Set DCO step and modulation to 16MHz
    
      P1OUT     = 0x02;                         // SYNC at P1.1 high powers down ADG714 SCLK and DIN buffers
      P1DIR     = 0x02;                         // Set P1.1 to output direction
    
      P1SEL     = 0x14;                         // Set special function register 1 for UCA0SIMO (P1.2) and UCA0CLK (P1.4)
      P1SEL2    = 0x14;                         // Set special function register 2 for UCA0SIMO (P1.2) and UCA0CLK (P1.4)
    
      UCA0CTL1  = UCSWRST;                      // Set USCI module in reset state
      UCA0CTL0  = (UCMSB | UCMST | UCSYNC);     // Clock idles low, data changed on first and captured on second edge, MSB first, master, synchronous mode
      UCA0CTL1 |= UCSSEL_2;                     // SMCLK as clock source
      UCA0BR0   = 1;                            // Pre-scaler 1
      UCA0BR1   = 0;
      UCA0CTL1 &= ~UCSWRST;                     // Release USCI module from reset
    
      __bis_SR_register( GIE );                 // Enable global interrupts
    
      while( 1 )                                // Endless loop
      {
        // ...
    
        if( something_happened )                // Event trigger to send data
        {
          adg714_start_transmission();          // Initiate transmission
        }
    
        // ...
      }
    }
    
    void adg714_start_transmission( void )
    {
      __bic_SR_register( GIE );                 // Disable global interrupts
      P1OUT &= ~0x02;                           // SYNC low powers up ADG714 SCLK and DIN buffers
      while( !(IFG2 & UCA0TXIFG) );             // Wait for free TX buffer
      UCA0TXBUF = adg714_bytes[0];              // Transmit first byte
      while( !(IFG2 & UCA0TXIFG) );             // Wait for free TX buffer
      UCA0TXBUF = adg714_bytes[1];              // Transmit second byte
      while( !(IFG2 & UCA0TXIFG) );             // Wait for free TX buffer
      UCA0TXBUF = adg714_bytes[2];              // Transmit third byte
      while( !(IFG2 & UCA0TXIFG) );             // Wait for free TX buffer
      UCA0TXBUF = adg714_bytes[3];              // Transmit fourth byte
      while( UCA0STAT & UCBUSY );               // Wait for complete transmission
      P1OUT |= 0x02;                            // SYNC high updates data
      __bis_SR_register( GIE );                 // Enable global interrupts
    }

    This takes only about 6µs to complete:

    But it blocks interrupts for the period of the transmission so that no other task will come in between. It depends on your application which method is the most useful. If you have a transmission from time time but then need highest update speed, I would use something like the last example. If there are lots of transmissions, but you do not need the fastest update, I would not use a method that blocks other interrupts most of the runtime.

    Dennis

  • Thank you very much Dennis. My application can tolerate up to 50us for all 32 bits to be updated, so the first method of triggering on RX will work just fine for me. I am going to get some ADG714 devices and test them out. Thanks a lot for all your suggestions.
  • Just a side note: There are interrupts with higher priority than the USCI interrupts - all the timers, for example. They will always be serviced first, so if you would have long interrupt functions (should always be avoided) with higher priority, your time for the transmission could be stretched. But I don't know the rest of your code and what interrupt sources you will be using in which intervals.

    Dennis

  • ok, that makes sense and that is what I was getting worried about. I have not yet thought about how to put the rest of my code together with the SPI code.

    Basically, the rest of the code contains a PWM and an ADC. Based on the readings from the ADC, I determine which select pin of a multiplexer should go high to allow the PWM through. Based on the ADC readings, I will also need to determine which switch of the SPI device needs to turn ON or OFF at a given time. So I  will have an ADC, PWM and a timer ISR.

    The ADC and the timer interrupt as you mentioned will further stretch transmission time. Because of this, I am actually thinking about simplifying the design and then use the implementation shown in figure 8 of ADG714 datasheet. And instead of using ADG739 as they have suggested, I will use a mux to eliminate an extra transmission time. This implementation will cut transmission time by 4 but of course the trade-off is only one chip can be selected at a time. 

    I will need to think some more about this and will likely ask you more specific questions soon.

    Thank you:)

  • Well, feel free to ask anything, but maybe you are worrying about your timing too much. It was just for basic understanding - here is the interrupt priority list for the MSP430G2553:

    As you can see, only the timers, the comparator and the watchdog have higher priority (and priority 30 and 31, of course). It is always good to have the working principle in mind. It also shows that the process with the most critical timing should be handled by TA1CCR0.

    But I guess you should build your circuit and do some tests with it.

    Dennis

  • Great, thank you. this chart was very helpful. 

    ok, so since we are on the interrupt topic, let me get some clarifications from you please. 

    In my other piece of code, I have a PWM configured in the main function. Then I have a timer interrupt which reads from an ADC and performs a task based on the reading. So the way I understand interrupts, if an interrupt is called, then the CPU will leave its main task in the main function momentarily to serve the interrupt. In my case, the PWM should stop for a short moment for the CPU to serve the interrupt, reading from ADC and performing another task based on it, and then go back to generation the PWM. similarly, when we run the SPI clock at CPU speed, the CPU does not have enough time to leave the main function. serve the RX interrupt and go back to its main function again. That is why I was seeing distorted signals. If what I said is correct, is there a rule about how much slower than the CPU clk an interrupt needs to run to not pose an issue? 

    Would you please correct me on anything I said here that was wrong. 

    I really appreciate your help here Dennis. You have been extremely helpful:) 

  • Sahar Elyahoodayan said:
    if an interrupt is called, then the CPU will leave its main task in the main function momentarily to serve the interrupt

    Yes, that's how it basically works. There is a difference if the processor is currently working on another interrupt - in this case the currently active one is finished first. After that, the next highest priority interrupt is serviced or if there is currently none, the main task is executed from the point it was interrupted. You will not loose any interrupt, except execution of one interrupt takes longer than the interval time of another one.

    Sahar Elyahoodayan said:
    In my case, the PWM should stop for a short moment for the CPU to serve the interrupt, reading from ADC and performing another task based on it, and then go back to generation the PWM.

    This depends on your PWM - the MSP can do PWM in hardware (OUTMOD_7) without any CPU time. If you use the hardware PWM you will not have any influence by anything.

    Sahar Elyahoodayan said:
    when we run the SPI clock at CPU speed, the CPU does not have enough time to leave the main function.

    The CPU will always leave the main function to serve interrupts. A problem occurs if your program only jumps from interrupt to interrupt without having time to do something in your main anymore. The problem with SPI running at CPU frequency is that it has no advantage to use interrupts. It could be even slower, I think. I don't know the exact number of CPU cycles it takes to enter the interrupt function (would have to look that up), but imagine this: Let's say it takes ten cycles from raising the interrupt flag to entering the ISR and start working on the code in it. Inside the ISR you now copy a byte into the TX buffer which also takes time, then leave the ISR which again adds cycles. We would have way more than ten now, but the USCI module runs in hardware, so as soon as the data byte is in the transmit buffer, it takes only eight cycles to shift the byte out. If the USCI module raises another interrupt flag, all the previous mentioned steps happen again. So the SPI itself is faster than your CPU with all the ISR overhead and your transmission is bottlenecked by the interrupt meachnism. In this case, the example with polling the USCI flags will be faster.

    Sahar Elyahoodayan said:
    is there a rule about how much slower than the CPU clk an interrupt needs to run

    The interrupt will never be slower than the CPU - it is handled at CPU frequency. I think you mean something like in which intervals an interrupt should happen. There is no rule for that - it depends on the specific application. Interrupts should be as short as possible to leave enough time for execution of the main code. And some tasks simply cannot be done with every processor. Another example: Imagine your processor has a maximum clock frequency of 10MHz and you now want a timer interrupt every 1µs to do some stuff inside the ISR - this would be an interrupt every ten clock cycles. This is no task a processor running at 10MHz can handle - it is simply not possible. You would need a faster processor.

    Dennis

  • Great explanation. Thanks a lot Dennis. I have a few follow up questions which I am trying to organize before I ask you.
  • Please help me understand a few more topics:

    As I mentioned before, I have a code where I generate PWM in hardware, read ADC from a floating pin to generate a 5 bit random number, and convert the random number to decimal. I want to then use that random number to drive 5 select pins of a multiplexer and eventually control the timing of closing and opening of some switches through SPI protocol. But let's not think about the SPI code for now so I can understand the concepts without complicating things too much for myself.  

    After having the above conversations with you regarding Interrupts, I realized that maybe I am putting a big chunk of my code for the timer ISR to take care of. Doing this has caused the ISR to take a longer time to finish before going back to the main function. This has caused the pulses I try to generate and hold for a specific duration using a counter to be elongated.

    I do not know how to balance between the amount of code I put in the main function and the ISR.

    My first approach was to only generate the PWM in the main code. I then move to a timer ISR loop and generate a random number to pull P1.0 to P1.4 high at random. This method worked but the time at which each pin stays high is longer than I want it to be. As I said, I use a counter to determine how long a pin should stay up. How do I determine how long each count inside of an ISR will take?

    My second approach is to move some part of the code to the main function. So, in addition to generating PWM in the main function, I would also read from an ADC and generate a random number in decimal and then move to ISR where P1.0 to P1.4 will be pulled high at random for a determined duration. Is this a better approach? I have not gotten this to work because I don't know how to have the code jump to the ISR loop and back to the main loop.

    I guess other approaches are to have an ADC interrupt in addition to a time interrupt. Or only an ADC interrupt and other tasks are done in the main loop. But I am confused about how to jump to an interrupt get a value, jump to another interrupt and then back to the main function. Please help me understand.

    Here is the code for my first approach if it helps:

    #include "msp430G2553.h"
    #include <stdint.h>
    
    
    void main( void )
    {
      // Stop watchdog timer
       WDTCTL = (WDTPW | WDTHOLD);
    
      // Set range to 1MHz
      BCSCTL1 = CALBC1_1MHZ;
      // Set DCO step and modulation to 1MHz
      DCOCTL = CALDCO_1MHZ;
    
      P1SEL    |= 0x40;                                     // Set special function of P1.6 to timer module
      P1DIR    |= 0x5F;                                     // Set to output direction
      P2DIR    |= 0X0F;
      P1OUT    |= 0x00;                                     // Set P1.0 ON, P1.1 OFF
      P2OUT    |= 0X00;
    
    
      // PWM frequency of 40kHz (25us)
      TA0CCR0 = 400;
      // Start with duty cycle base
      TA0CCR1 = 60;
      // Reset/set mode
      TA0CCTL1 = OUTMOD_7;
      // SMCLK, divider 1, up-mode, clear, overflow interrupt enabled
      TA0CTL = (TASSEL_2 | ID_0 | MC_1 | TACLR | TAIE);
    
    
      // Enable global interrupts
      __bis_SR_register( GIE );
    
      // Endless loop - main program
      while( 1 );
    
    }
    
    
    // Timer 0 A1 interrupt service routine
    #pragma vector = TIMER0_A1_VECTOR
    __interrupt void Timer0_A1_ISR( void )
    {
        volatile uint8_t A0;            //store ADC bit here
        volatile uint8_t rn = 11111;    //5 bit random number;
        volatile uint8_t n = 6;         //loop through 5 bits 
        volatile uint8_t dec = 0;       // decimal value 0-31
        volatile uint8_t rem;           // remainder
        volatile uint8_t base = 1;      //base
        static uint8_t Flag = 1;        //flag 
    
        static uint8_t counter = 5;         //counter
    
            //state name
        static uint8_t S0 = 0;
        static uint8_t S1 = 0;
        static uint8_t S2 = 0;
    
        ADC10CTL1 |= INCH_5;        //read from P1.5, floating pin
        ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON;
        ADC10CTL0 |= ENC + ADC10SC;
    
    
        TA0CTL &= ~TAIFG;                                   // Clear interrupt flag
    
    
        //generate 5 bit ADC and convert to a decimal number 
          if ((Flag == 1) || (dec == 0))
          {
    
          while (n != 0)
          {
    
          while(ADC10CTL1 & ADC10BUSY);
          A0 = ADC10MEM & 0x01;
    
          if (A0)
          {// comp. if LSB is 1
          n--;
          rn ^= (1 << n);
          }
          // if yes save LSB = 1 to left-shifted
          // register rn
          else if (!A0)
          {
          n--;
          rn ^= (0 << n);
          }
          }
          // if not save LSB = 0 to left-shifted
          // register rn
    while (rn > 0)
             {
                 rem = rn % 10;
                 dec = dec + rem * base;
                 base = base * 2;
                 rn = rn / 10;
             }
    
          if (!n)
          {
              n = 6;
              Flag = 0;
          }
          }
    
          //Pull P1.0 to P1.4 high based on the generated random number and hold for counter numeber of times. 
    
          if ((Flag == 0) && (dec != 0))
          {
              if ( !(--counter) )
                                        {
                                            if (!S0 && !S1 && !S2 )
                                            {
                                                
                                                P1OUT = dec;                        
                                                P2OUT = 0X0C;
                                                counter = 5;                        
    
                                                //Flag to go to next state
                                                S0 = 0;
                                                S1 = 1;
                                                S2 = 0;
    
                                            }
    
                                            else if (!S0 && S1 && !S2 )
                                            {
                                    
                                                P1OUT = 0X00;                       
                                                P2OUT = 0X00;
                                                counter = 5;                        
    
                                                S0 = 1;
                                                S1 = 0;
                                                S2  = 0;
    }
    
                                            else if (S0 && !S1 && !S2 )
                                            {
                                
                                                P1OUT = dec;                        
                                                P2OUT = 0X05;
                                                counter = 5;                    
    
                                    
                                                S0 = 1;
                                                S1 = 1;
                                                S2 = 0;
    
                                            }
    
                                            else if (S0 && S1 && !S2 )
                                            {
     
                                                P1OUT = 0X00;                   
                                                P2OUT = 0X00;
                                                counter = 5;                        
    
                           
                                                S0 = 0;
                                                S1 = 0;
                                                S2 = 1;
    
                                            }
    
                                            else if (!S0 && !S1 && S2 )
                                            {
                                                Flag = 1;
                                                S0 = 0;
                                                S1 = 0;
                                                S2 = 0;
                                            }
                              }
    
    
    
    
          }
    
          }
    

**Attention** This is a public forum