Yahoo Groups archive

AVR-Chat

Index last updated: 2026-04-28 22:41 UTC

Thread

Re: Array of Long

Re: Array of Long

2009-03-06 by Graham Davies

--- In AVR-Chat@yahoogroups.com, David VanHorn <microbrix@...> wrote:

> I have an array of longs that
> I need to feed out my Uart ...

David, in the statement:
UDR = &(Proc_Data[Proc_Data_Out_Index])+i;
on the right hand side you take the address of an array element and add i.  What is puzzling you is why the result jumps up four at a time.  The reason is that the address of the array element is a typed pointer.  In other words, the compiler knows that it's the address of a long and will treat it as such.  For each "one" you add to the value of this pointer, the compiler will move forward four bytes, so as to point to the next long object in memory.

A solution is to discard the type by casting the address to a number.

A better solution would be to cast the address of the entire array to be a pointer to bytes.  It is then clearer in the program text what you are trying to do, which is to treat an array of longs as an array of bytes for some specific purpose.  Remember to multiply the number of longs in the array by sizeof ( long ) to get the number of bytes.  Or, if the length of the array is known at compile time and you want to send it all, just use sizeof ( Proc_Data ).

Graham.

Array of Long

2009-03-06 by David VanHorn

I am a bit puzzled. (and new to working in C)

I have an array of longs that I need to feed out my Uart.
Obviously the uart can't take more than a char.

The code below shows some of the ideas I've tried, but in all cases,
the ASM shows me that the pointer will be bumped four bytes, not one.

What's the best way to get this data to my Uart?

Yes, I CAN sit and spin for the UDR to be ready.

void Do_Serial_Output(void)
{		
   unsigned char i = 0;
   unsigned char t = 0;
   if (0 < Proc_Data_Size) { // If there's data to send..	
      while (	i<4 ) {
      while (!(UCSRA & (1<< UDRE))) {}
            //memcpy(&t,&(Proc_Data[Proc_Data_Out_Index])+i,1);
            //UDR = t;
            //UDR = (char)(*((char*)(&(Proc_Data[Proc_Data_Out_Index])+i)));
            UDR = &(Proc_Data[Proc_Data_Out_Index])+i;
            ++i;
       }	

      Proc_Data_Size--;						
      Proc_Data_Out_Index++;	
      if (Proc_Samples < Proc_Data_Out_Index) Proc_Data_Out_Index =
0;	// Handle wrap
      }
}

-- 

"The very powerful and the very stupid have one thing in common. Instead of
altering their views to fit the facts, they alter the facts to fit their
views... which can be very uncomfortable if you happen to be one of the
facts that needs altering." Doctor Who, Face of Evil

Re: [AVR-Chat] Re: Array of Long

2009-03-06 by David VanHorn

On Fri, Mar 6, 2009 at 9:55 AM, Graham Davies <Yahoo37849@ecrostech.com> wrote:
> --- In AVR-Chat@yahoogroups.com, David VanHorn <microbrix@...> wrote:
>
>> I have an array of longs that
>> I need to feed out my Uart ...
>
> David, in the statement:
> UDR = &(Proc_Data[Proc_Data_Out_Index])+i;
> on the right hand side you take the address of an array element and add i.  What is puzzling you is why the result jumps up four at a time.  The reason is that the address of the array element is a typed pointer.  In other words, the compiler knows that it's the address of a long and will treat it as such.  For each "one" you add to the value of this pointer, the compiler will move forward four bytes, so as to point to the next long object in memory.

I  understand that part.  The compiler is treating the array as I defined it.
But obviously I can't feed a long to the UART...


> A better solution would be to cast the address of the entire array to be a pointer to bytes.

? :)


>It is then clearer in the program text what you are trying to do, which is to treat an array of longs as an array of bytes for some specific purpose.  Remember to multiply the number of longs in the array by sizeof ( long ) to get the number of bytes.  Or, if the length of the array is known at compile time and you want to send it all, just use sizeof ( Proc_Data ).

The array size is known at compile time, but not the number of
elements in the array.
A processing routine puts data into this array, two longs per
millisec.  I have to transmit the data via the uart.
All the processing happens during the T0 ISR, so it's ok if I'm
sitting here waiting for the uart. Nothing else is happening in the
machine, so I don't expect any timing issues.

I'm just frustrated because what I want would be dead easy in ASM, but
at least half of the point of the exercise is to learn C.

I'd really like to see a "C cookbook", not a language manual, and not
a project, but a collection of commonly used functions.

Re: [AVR-Chat] Array of Long

2009-03-06 by David Kelly

On Fri, Mar 06, 2009 at 09:41:30AM -0500, David VanHorn wrote:
> I am a bit puzzled. (and new to working in C)
> 
> I have an array of longs that I need to feed out my Uart.
> Obviously the uart can't take more than a char.
> 
> The code below shows some of the ideas I've tried, but in all cases,
> the ASM shows me that the pointer will be bumped four bytes, not one.

As Graham suggests you can override the compiler using casts but I
suggest a union would be cleaner. I use something like this quite a lot:

typedef union {
	struct {
		uint8_t, a, b, c, d;
	} u8;
	struct {
		// verify if this should be "dc, ba" or something
		// so that it makes sense with u8 above
		uint16_t ab, cd;
	}
	uint32_t u32;
} UNION32_t;

In your case you might do this:

union {
	uint8_t  u8[ PROC_DATA_SIZE * sizeof(uint32_t)];
	uint32_t u32[PROC_DATA_SIZE];
} Proc_Data;

Then when you want the long version use Proc_Data.u32[] and when you
want it byte at a time use Proc_Data.u8[]. This doesn't take any extra
code space or CPU cycles.

The .u32 and .u8 at the ends are a lot cleaner than forcing casts with
pointers.

Another way to do this is to make a putsc( void *vp, uint8_t count )
routine that takes a pointer and byte count to be sent out the UART. In
the putsc() routine you will have to cast the void * to uint8_t in order
to index or do pointer arithmetic. The void * in the declaration will
mute any complaints about the type of pointer you are passing. Maybe
something like this:

uint8_t
putsc( void *vp, uint8_t count )
{
    uint8_t *cp = (uint8_t*)vp;  // this might not allocate or cost anything
    uint8_t i;

    for( i = 0 ; i < count ; i++ ) {
        SCI = cp[i];
        ...
    }
    return count;
}

-- 
David Kelly N4HHE, dkelly@HiWAAY.net
========================================================================
Whom computers would destroy, they must first drive mad.

Re: [AVR-Chat] Array of Long

2009-03-06 by Raymond Hurst

You need to do something similar to this:

long test[10] = {....};

UDR = ((char)test[i]) & 0xFF;
UDR = ((char)test[i] >> 8) & 0xFF;
UDR = ((char)test[i] >> 16) & 0xFF;
UDR = ((char)test[i] >> 24) & 0xFF;
i += 1;

David VanHorn wrote:
> 
> 
> I am a bit puzzled. (and new to working in C)
> 
> I have an array of longs that I need to feed out my Uart.
> Obviously the uart can't take more than a char.
> 
> The code below shows some of the ideas I've tried, but in all cases,
> the ASM shows me that the pointer will be bumped four bytes, not one.
> 
> What's the best way to get this data to my Uart?
> 
> Yes, I CAN sit and spin for the UDR to be ready.
> 
> void Do_Serial_Output(void)
> {
> unsigned char i = 0;
> unsigned char t = 0;
> if (0 < Proc_Data_Size) { // If there's data to send..
> while ( i<4 ) {
> while (!(UCSRA & (1<< UDRE))) {}
> //memcpy(&t,&(Proc_Data[Proc_Data_Out_Index])+i,1);
> //UDR = t;
> //UDR = (char)(*((char*)(&(Proc_Data[Proc_Data_Out_Index])+i)));
> UDR = &(Proc_Data[Proc_Data_Out_Index])+i;
> ++i;
> }
> 
> Proc_Data_Size--;
> Proc_Data_Out_Index++;
> if (Proc_Samples < Proc_Data_Out_Index) Proc_Data_Out_Index =
> 0; // Handle wrap
> }
> }
> 
> -- 
> 
> "The very powerful and the very stupid have one thing in common. Instead of
> altering their views to fit the facts, they alter the facts to fit their
> views... which can be very uncomfortable if you happen to be one of the
> facts that needs altering." Doctor Who, Face of Evil
> 
> 

-- 
Ray Hurst
949-202-6037

Re: [AVR-Chat] Array of Long

2009-03-06 by Raymond Hurst

Ooops...this won't work..it needs to be this

long test[10] = {....};

UDR = (char)( test[i]        & 0xFF);
UDR = (char)((test[i] >> 8)  & 0xFF);
UDR = (char)((test[i] >> 16) & 0xFF;)
UDR = (char)((test[i] >> 24) & 0xFF);
i += 1;
Ray

Re: [AVR-Chat] Array of Long

2009-03-06 by David VanHorn

On Fri, Mar 6, 2009 at 11:35 AM, Raymond Hurst <rhurst2@cox.net> wrote:
> You need to do something similar to this:

That's what I ended up with.
Even more fun, because I dispensed entirely with the output buffer,
and stuffed it into the T0 interrupt with almost everything else.

Processing the arrays is still taking more time than I'd like but I
cheated, processing the "A" array, then starting to send the bytes of
A while processing the B array.

    while (!(UCSRA & (1<< UDRE))) {};
UDR = (c >> 16);
//Debug_DDR	|= (1 << Debug_Pin);	// Output
//Debug_Port	|= (1 << Debug_Pin);	// High	
d = 0;
d = (d + pgm_read_word_near(Log_Table + Histogram_B[0]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[1]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[2]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[3]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[4]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[5]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[6]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[7]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[8]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[9]));
d = (d + pgm_read_word_near(Log_Table + Histogram_B[10]));
//Debug_Port &= ~(1 << Debug_Pin);			// Low

d is a long that stores the B array.
I might not need a long either, I may be able to prove that the ouput
will always fit in a word.

I'm processing nearly a seconds worth of 16 bit data from two sensors,
every millisecond.
:)

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.