ASM Register vs. C Array

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

ASM Register vs. C Array

1,047 Views
LiveMike
Contributor II

wasnt sure where to post this so i stuck with my 8 & 16 bit forum, always good answers :smileyhappy:

 

 

In assembly I have an 8 bit register, GPREG

 

LDA #$6D        ; which is decimal 109

STA GPREG

 

gives me 01101101

 

lets say i want an LED to turn on off according to that pattern

 

LSR GPREG

(check carry bit set LED on/off etc. for 8 bits)

 

now the led blinks in an order unique to "decimal 109"

 

how would i accomlpish this in C?

 

i have "decemial 109" or even "hex 6D"

i have:

 

byte b;

b = 109;  // my variable type in this case is a byte, and i CANT change that

 

do i have to right an algorith creating an array?

 

for i = 0 to 7 {

if b divided by whatever*i has a remander or not theh pattern[i] = 0 or 1

} // sorry for ugly pseudo code

 

so now my "pattern[]" has 8 ints 0 and 1s, and matches my GPREG,

 

But is there an easier way?

 

byte b = 109;

if b.0

if b.1

if b.2 (bit 2 "third bit") is 0 then LED off

 

or something like that?

 

thanks in advance for the help

 

-mike

Labels (1)
Tags (1)
0 Kudos
4 Replies

476 Views
bigmac
Specialist III

Hello Mike,

 

There is no need to use an array - you can also use a shift operation in C.  The primary difference is that you do not have direct access to the carry flag (without use of a special "intrinsic" function), so the usual approach is to test the (LS) bit prior to doing the right shift.

 

The following assembly sub-routine will generate the LED sequence, and is what might be used in practice.  I have made use of the stack for temporary storage, which is akin to using local variables in C.

 

LED       EQU    0              ; PTAD0


; LED SEQUENCE OUTPUT
; On entry, ACC = LED pattern
;           X = bit period (multiples of 10 ms)

 

LED_SEQ:  PSHA                  ; Blink pattern (1,SP)
          LDA    #8             ; Bit counter
LS1:      LSR    1,SP           ; CF is current bit state
          BCC    LS2            ; Branch if off state
          BSET   LED,PTAD       ; Turn LED on
          BRA    *+4            ; Skip next always
LS2:      BCLR   LED,PTAD       ; Turn LED off
          JSR    WAIT           ; X = multiples of 10 ms
          DBNZA  LS1            ; Loop for next state
          AIS    #1             ; Adjust stack pointer
          RTS

 

The following C function should operate similarly to the above code.

 

#define LED  PTAD_PTAD0         // Would usually be in a header file


void LED_seq( byte pattern, byte bit_time)
{
   byte i;                      // Bit counter

   for (i = 0; i << 8; i++) {
      if (pattern & 1)          // Test bit-0
         LED = 1;               // Turn LED on
      else
         LED = 0;               // Turn LED off
      pattern >>= 1;            // Shift right
      wait( bit_time);          // Multiples of 10 ms
   }
}

 

If you were to use a global variable for the bit pattern, rather than the function parameter, it is likely that the function would occupy more bytes, unless the global variable is explicitly placed within zero page RAM.

 

Regards,

Mac

 

0 Kudos

477 Views
LiveMike
Contributor II

 

#define LED  PTAD_PTAD0         // Would usually be in a header filevoid LED_seq( byte pattern, byte bit_time){   byte i;                      // Bit counter   for (i = 0; i << 8; i++) {      if (pattern & 1)          // Test bit-0         LED = 1;               // Turn LED on      else         LED = 0;               // Turn LED off      pattern >>= 1;            // Shift right      wait( bit_time);          // Multiples of 10 ms   }}

 

 

this looks great mac, but (of course) i have a few questions...

so the "byte" type in C is like a register?  as opposed to maybe int? you cant shift ints correct?

int foo;foo >>=1;

 that wouldnt work right?

but we can operate on bytes like ints correct?

byte bar;bar = 50;bar = bar - 48;

 this would make bar 2 correct?  then it still stored as 0000010 correct?

 

next question is...

"pattern & 1" will always give you 1 or 0 correct?  so why have the if statement?

cant you just do LED = pattern & 1; ???

 

last question...

i had been looking for somethign to "wait", so i see you have wait(7); that would wait 70ms correct??

 

is there a wait for microseconds (us)?  in assembly i use subroutines with NOP.

in C though this has been more difficult. sometimes it seems i to a for loop or while loop and try to fill it with "asm (NOP);" but it seems that i can get the right amount of loops.

right now I use:

int a;a = 0;while (a < 565){  a++;}

 to get a 500us delay.  i know this is based off of the JM16's speed and clock settings, but it works, I just wandering if there is a wait() for microsecond intervals??

 

and of course THANK YOU THANK YOU for all of your help!!! :smileyhappy:

 

-mike

 

0 Kudos

477 Views
bigmac
Specialist III

Hello Mike,

 

Within the header file for the MCU derivative, you should find the following entries -

typedef unsigned char byte;

typedef unsigned int word;

 

What this means is that you can use the byte data type in lieu of the standard data type of unsigned char.  Similarly with using word in lieu of unsigned int.  With C we refer to a "variable" as having a specific data type.  The word "register" has a very specific meaning in C.

 

The first example that you give would require that variable foo be initialised prior to the shift operation.

foo >>= 1;      // This is short-hand for

foo = foo >> 1;

 

Yes, you could use -

LED = pattern & 1;

 

Good observation!  That is one I missed in attempting to demonstrate the equivalence of the assembly and C snippets.

 

I was not specific about the wait function, but you will obviously need one.  While the looping method can be calibrated to produce the right amount of delay for a specific bus frequency, a better method is to make use of a timer module.  An approach that is often used is to generate "tick" interrupts at regular intervals, typically 1 to 10 milliseconds.  This can be used for general delay timing, provided you can tolerate a timing uncertainty of one tick interval - if the required timing parameter is N intervals, the actual delay will fall somewhere between N-1 and N intervals.

 

The chosen tick interval should not be too short, where the frequent execution of the ISR code would occupy a significant percentage of the processing time.  With say, 500 microsecond interval and a 10MHz bus frequency, the number of cycles between interrupts would be 5000 - probably acceptable with short ISR code.  However, a tick period of 50 microseconds would appear unacceptable in most instances.

 

The following code snippet assumes use of a TPM channel, using software compare mode, although there are other possible alteratives. Assume a 10 MHz bus frequency, and a TPM prescale factor of 4, the following ISR code is a possibility for a tick interval of 5ms.

 

#define INCRVAL 12500        // 5ms interval with 10MHz bus, TPM prescale 4

 

volatile word delay_cnt = 0; // volatile modifier is required for this global variable

 

__interrupt 9 void ISR_TPM1C0( void)

{

   TPM1C0V += INCRVAL;  // Next compare value

   TPM1C0_CH0F = 0;     // Clear flag

 

   if (delay_cnt)  delay_cnt--;

}

 

The delay function -

 

void wait( word delay)

{

   delay_cnt = delay;

   while (delay_cnt)    // Wait for timeout

      __RESET_WATCHDOG();  

}

 

Regards,

Mac

0 Kudos

477 Views
kef
Specialist I

GPREG = bitpattern;

for(i = 0; i < 8; i++)

{

    if(GPREG & 0x80) bit_is_set();

    GPREG <<= 1;

}

 

0 Kudos