USART / UART data sampling timing problem

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi there I am using ADS1252 and AVR644p. I think I am having some problem with my USARTs.

My AVR has 2 USARTs and I am configuring USART0 in SPI mode - for reading from ADC.

Data is stored in UDR0 (data register of USART0 - ADC utility)and saved as to Data[2..0]- 3 bytes,
then ToUsart[2..0] = Data[2..0],
and lastly assigning ToUsart[2..0] to UDR1 (data register of USART1 -RS232 utility)

My code reading from ADC using USARTinSPImode looks like this

//function for reading data from adc using usart spi
void USARTSPI_ReadADS1252(void)
{
            //declare 8bit WatchDRDY to detect DRDY mode
            unsigned char WatchDRDy;

    			//Watch for Data ready
            WatchDRDy = (PINC & 0x02 );
			//if Data ready occurs, do nothing
			while (WatchDRDy == (PINC & 0x02 ))
			{
                //do nothing
			};

            // make the whole delay to 22us to pass through the DRDY mode
            _delay_us ( 4);

			//PORTC0 toggle for debugging purpose
			PORTC ^= (1);


            //Write to data register to initiate data transfer

            UDR0= 0;
            //Wait till you've received 8 bits
            //Do nothing  when Receive Complete Flag is ZERO (  means when it has not yet completely received data)
            while ((USART_CSR_A_Receive_Flag  & UCSR0A) == 0)
            {
            }
            //Read the data
            //UDR0 is the 8- bit USART Data Register
            Data[2] = UDR0;


            UDR0 = 0;
            while ((USART_CSR_A_Receive_Flag  & UCSR0A) == 0)
            {
            }
            Data[1] = UDR0;


            UDR0 = 0;
            while ((USART_CSR_A_Receive_Flag & UCSR0A) == 0)
            {
            }
            Data[0] = UDR0;

};

My USART_rs232 code looks like this

void USART_RS232_Interfacing(void)
{
	//formula to delay and count 8 times - to fool the optimiser
    int Loop_StopFlag = 0;
    int Loop = 0;

    while ( Loop_StopFlag == 0)
    {
        Loop = (Loop + 1) & 7;

        if (Loop == 0)
        {
            Loop_StopFlag = 1;
            break;
        }
    }
	//at the 8th count, Loop will give 0
	if (Loop_StopFlag == 1 )
	{
		//get Data[] into another variable ToUsart1[]
		ToUsart1[0] = Data[0];
		ToUsart1[1] = Data[1];
		ToUsart1[2] = Data[2];


        //stream location counter initialisation
        int streamLoc = 0;

        //stream out data from  ToUsart1[0..2]
        while (streamLoc < 3)
        {
            // Send out the byte value in the variable ToUsart[0..2] to dara register of Usart_RS232
            UDR1 = ToUsart1[streamLoc];

            // Do nothing until UDR is ready for more data to be written to it by checking register empty flag
            while ((UCSR1A & USART_CSR_A_Data_Register_Empty_Flag  ) == 0) {}

            // increment stream location counter 0..2
            streamLoc++;
        }

        while ((UCSR1A & USART_CSR_A_Data_Register_Empty_Flag  ) == 0) {}
	}

On oscilloscope, the data sampling timing controlled by XCK0 shows inconsistant sampling intervals. (The interval between each set of 24bits data logging is irregular). I think this is a problem caused by UART. Can you see how?

Thanks in advanced :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Data is stored in UDR0 (data register of USART0 - ADC utility)and saved as to Data[2..0]- 3 bytes,
then ToUsart[2..0] = Data[2..0],
and lastly assigning ToUsart[2..0] to UDR1 (data register of USART1 -RS232 utility)
I'm soooo confused. :roll: but that's my old brain I guess.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are inferring synchronous UART with the AVR as master. Did you remember to set the data direction register for port B0 (XCK0) to an output? One would expect to see inconsistent timing between UART bytes, but not between UART bits.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi John, sorry for my bad English. I mean I moved my data from UDR0 to UDR1 by assigning them to different variables to avoid confussion.

Mike, I did set PORTB0 as output and the consistancy I meant was between sets of 24bits => wrong timing between a block of 3bytes. (Not bits)

Thanks :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Stupid question - WHY use a USART for SPI and not the built in SPI hardware???

Randy

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

rstahlhu wrote:
Stupid question - WHY use a USART for SPI and not the built in SPI hardware???
One possibility is the 644P has a USART SPI master mode which has data buffers not found in the dedicated SPI hardware. What if you are already using the dedicated SPI hardware for something else and you want another SPI master?

Different delays (within reason) between the 3 bytes would result if your program code isn't deterministic (always uses the same number of CPU cycles to get the next 3 bytes). Its kind of difficult to be deterministic if other interrupts are used. Since the SPI USART0 is the master, the time when XCK0 is idle shouldn't matter to the slave as long as there is a Slave Select output from the master to the slave to guarantee XCK0 bit synchronization.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh ya. I am reserving built-in SPI for uSD later. Anyway thanks for replying :)

Quote:
if your program code isn't deterministic (always uses the same number of CPU cycles to get the next 3 bytes).

I don't really understand this phrase. How do you "use the same number of CPU cycles"? As far as I know, the XCK0 will clock by itself once I write to UDR0(eg. UDR0 = 0). As for my ADC, the data is controlled merely by XCK0 clocking, and I am not writing any code to control it.

Also, I am not using interrupts at the moment. (ADC is in synch. mode & RS232 is in asynch. mode - I don't know why but setting RS232 to work in synch. mode doesn't work).

You got your point about using SS but have a look at this table. I got it from AVR644p datasheet(pg205).

Quote:

USART_MSPIM SPI Comment
TxDn MOSI Master Out only
RxDn MISO Master In only
XCKn SCK (Functionally identical)
(N/A) SS Not supported by USART in MSPIM

I understand from datasheet that SS is used to synchronise master and multiple slaves after a data pack. But I don't think I have the SS option here when using USART_SPI mode. Besides, I am only using one slave for each of the USART (ie. ADC for USART0 & RS232 for USART1). So I am not sure if it is applicable here. Do you have any other ideas?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Deterministic means your code always runs exactly the same way with the same number of CPU cycles no matter what. Typically any program code beyond the simplest code must be specifically written to achieve a deterministic run state. Every calculation and branch might take slightly longer or slightly less to execute if not a whole lot longer or less in the case of loops. Writing deterministic code is often used to help keep security encryption programs secure against external attacks. So, if you get 3 SPI bytes, then go off to send them to the USART and do some buffer management or anything that might not run in exactly the number of CPU cycles as last time, you will see a different delay between each set of 3 SPI bytes (just because the code between the 3 byte SPI operation has slightly different run times). Active interrupts (which I see you are not using) make it almost impossible to write deterministic code. You do not need deterministic code. I was only pointing out that not having it was probably why you see different time delays between 3 byte transfers.

What the data sheet is telling you is SS is not supported in the USART in SPI master mode hardware. You must choose an AVR output pin and control it with program code to do the master SS job. SS (Slave Select) tells the specific SPI slave its connected to "here comes the beginning of a new SPI transfer". Most slave SPI hardware will clear its internal SPI bit counter on the SS signal edge when its asserted. Now SS can remain asserted for as long as you want (8, 16, 24, 32,... bytes, etc.) or as long as your SPI slave requires, but sometime you will need a SS assertion to synchronize the transfer. In your case with 3 byte transfers from the same SPI slave, it probably makes sense to assert SS and transfer all 3 bytes, then un-assert SS (as long as your SPI slave is happy with this). If you never synchronize and noise causes a false XCK0 pulse, the slave SPI will always be 1 bit count off and never recover until you reset or power cycle your hardware.