Yahoo Groups archive

AVR-Chat

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

Message

Re: [AVR-Chat] Re: Mixing C and assembly with special requirements.

2012-03-27 by fireweaver

On 3/26/2012 3:46 PM, Don Kinzer wrote:
> --- In AVR-Chat@yahoogroups.com, fireweaver<firewevr@...>  wrote:
>> The decoder I have does its thing in about 28 cycles.  As a C
>> interrupt routine, it is well over 100 cycles and may not be
>> able to keep up with the encoder.
> If you are willing to post the existing assembly code and provide an upper limit on the number of cycles that is acceptable, I expect that you would have several people rise to the challenge to make it avr-gcc compatible or re-implement it so that it is compatible.
>
> Don Kinzer
> ZBasic Microcontrollers
> http://www.zbasic.net
>

Here is the code.  I don't know how this will appear since the group 
forbids attachments.
Use a fixed width font like Courier to make it look right.
The general idea is to control a motor which can run up to 3000 RPM.  It 
has an built-in
encoder with 400 counts (at 4X) per revolution.


; SINGLE CHANNEL QUADRATURE DECODER

;*******************************************************************************;
;                                                                               
;
;  This is the quadrature decoder.  This decoder is designed to decode 
two      ;
; channels to a resolution of one part in 2^24.   It is designed to run 
as fast ;
; as 
possible.                                                                  ;
;                                                                               
;
; Selling 
points:                                                               ;
;       1.  One channel to 24-bit 
precision.                                    ;
;       2.  Very fast execution time = 25 cycles worst 
case.                    ;
;       3.  Small code 
size.                                                    ;
;       4.  Extensible to more channels (as dedicated 
encoder)                  ;
; Weak 
points:                                                                  ;
;       1.  Commandeers 4 registers for its own 
use.                            ;
;                                                                               
;
;*******************************************************************************;

.include        "m168Adef.inc"

;*******************************************************************************;
;   Defined by original 
project                                                 ;
;                                  
ATmega168                                    ;
;                                 
/----U----\                                   ;
;                             PC6 | 01   28 | 
PC5                               ;
;               (X-axis I in) PD0 | 02   27 | 
PC4                               ;
;               (X-axis Q in) PD1 | 03   26 | 
PC3                               ;
;               (X error out) PD2 | 04   25 | 
PC2                               ;
;                             PD3 | 05   24 | 
PC1                               ;
;                             PD4 | 06   23 | 
PC0                               ;
;                             VCC | 07   22 | 
GND                               ;
;                             GND | 08   21 | 
AREF                              ;
;                             PB6 | 09   20 | 
AVCC                              ;
;                             PB7 | 10   19 | 
PB5                               ;
;                             PD5 | 11   18 | 
PB4                               ;
;                             PD6 | 12   17 | 
PB3                               ;
;                (duty cycle) PD7 | 13   16 | 
PB2                               ;
;                             PB0 | 14   15 | 
PB1                               ;
;                                 
\---------/                                   ;
;                                                                               
;
; (duty cycle) is used to see how long the routine 
runs                         ;
;                                                                               
;
;                                                                               
;
; PORTD bits are laid out as 
follows:                                           ;
.equ   CH_X0    = PD0   ; Channel A inphase in
.equ   CH_X1    = PD1   ; Channel A quadrature in
.equ   ERR_X    = PD2   ; Channel A error signal out
.equ   OC2B     = PD3   ; Timer overflow bit (diagnostic output).
.equ   Q_DEBUG  = PD7   ; Duty cycle informs on CPU usage ()
;                                                                               
;
; Reserved register 
assignments.                                                ;
;                                                                               
;
; Encoder 
management                                                            ;
        .def    encoder_state    = R9

; X-count accumulator (dedicated to 
encoder)                                    ;
        .def    X_count_0        = R21   ; low byte
        .def    X_count_1        = R22
        .def    X_count_2        = R23   ; high byte

; This code is may be located anywhere in 
memory.                               ;
;                                                                               
;
;        _______         ___________         _______     ___         
___        ;
; A |___/   |   \___|___/   |   |   \___|___/   |   \___/   \___|___/   
\___/   ;
;   |   |   |___|___|   |   |___|   |   |___|___|   |   |___|   |___|   
|___    ;
; B \___|___/   |   \___|___/   \___|___/   |   \___|___/   \___/   
\___/   \   ;
;    -6  -5  -4  -3  -2  -1   0   1   2   3   4   5   6   ?   ?  OK   
?   ?     ;
;                                                                               
;
;   |                  normal operation                 | error 
codes       |   ;
;                                                        ? = Error, K = 
Okay    ;
;                                                                               
;
; The encoder is periodically sampled.  Each sample is compared to the 
previous ;
; sample giving one of 16 possible choices.  These choices funnel into 
four     ;
; possible actions, depending on how the bits change between 
samples.           ;
;  Sampling rate is required to be at least twice the rate of incoming 
encoder  ;
; pulses to ensure accurate 
counting.                                           ;
;                                                                               
;
; These actions 
are:                                                            ;
;        Increment - add one to the count 
register                              ;
;        Decrement - subtract one from the count 
register                       ;
;        Idle - inputs did not change, do 
nothing                               ;
;        Error - should never happen, both inputs changed at the same 
time.     ;
;               If the error signal comes and goes, it is a sign that 
the input ;
;               is changing too fast for the decoder to keep up 
with.           ;
;                                                                               
;
; A,B     
A,B                                                                   ;
; Was     Is      Do 
This                                                       ;
; 
------------------------------                                                
;
; 00      00      
idle                                                          ;
; 00      01      
increment                                                     ;
; 00      10      
decrement                                                     ;
; 00      11      
error                                                         ;
;                                                                               
;
; 01      00      
decrement                                                     ;
; 01      01      
idle                                                          ;
; 01      10      
error                                                         ;
; 01      11      
increment                                                     ;
;                                                                               
;
;                                                                               
;
; 10      00      
increment                                                     ;
; 10      01      
error                                                         ;
; 10      10      
idle                                                          ;
; 10      11      
decrement                                                     ;
;                                                                               
;
; 11      00      
error                                                         ;
; 11      01      
decrement                                                     ;
; 11      10      
increment                                                     ;
; 11      11      
idle                                                          ;
;*******************************************************************************;

.cseg

.org    0x100

Quadrature_Decoder:
; do all preparation in advance         ;(cycles)
         lsr     encoder_state           ;(1)  current X,Z state becomes 
previous
         in      ZH,PIND                 ;(1)  sample the inputs once
; update the state of the X-input
         bst     ZH,CH_X1                ;(1)
         bld     encoder_state,1         ;(1)
         bst     ZH,CH_X0                ;(1)
         bld     encoder_state,3         ;(1)  copy port bits to current 
X state
;
decode_X:
         ldi     ZH,high( X_actions)     ;(1)  load once, doesn't change.
         mov     ZL,encoder_state        ;(1)
         andi    ZL,15                   ;(1)
         subi    ZL,0xFF-low(X_actions)  ;(1)
         ijmp                            ;(2)  do an X action
         ;
X_actions:
         .db     low(X_idle), low(X_increment), low(X_decrement), 
low(X_error)
         .db     low(X_decrement), low(X_idle), low(X_error), 
low(X_increment)
         .db     low(X_increment), low(X_error), low(X_idle), 
low(X_decrement)
         .db     low(X_error), low(X_decrement), low(X_increment), 
low(X_idle)

X_error:    ; both inputs changed at same time, or encoder turning too fast.
         sbi     PORTD,ERR_X             ;(2) "X error" = 1
X_idle:     ; not moving
         reti                            ;(2)

X_increment:    ; counting up
         cbi     PORTD,ERR_X             ;(2) "X error" = 0
         subi    X_count_0,low(-1)       ;(1)
         sbci    X_count_1,byte2(-1)     ;(1)
         sbci    X_count_2,byte3(-1)     ;(1)
         reti                            ;(4)  longest path = (13)

X_decrement:    ; counting down
         cbi     PORTD,ERR_X             ;(2) "X error" = 0
         subi    X_count_0,low(1)        ;(1)
         sbci    X_count_1,byte2(1)      ;(1)
         sbci    X_count_2,byte3(1)      ;(1)
         reti                            ;(4)



;*******************************************************************************;
;                                  End of 
decoder                               ;
;*******************************************************************************;

;AVRASM: AVR macro assembler 2.1.43 (build 48 May 30 2011 10:07:37)
;Copyright (C) 1995-2011 ATMEL Corporation
;
;D:\videos\quadrature_encoder_1_1.s(20): Including file 
'D:\videos\m168Adef.inc'
;
;ATmega168A memory use summary [bytes]:
;Segment   Begin    End      Code   Data   Used    Size   Use%
;---------------------------------------------------------------
;[.cseg] 0x000200 0x00023e     46     16     62   16384   0.4%
;[.dseg] 0x000100 0x000100      0      0      0    1024   0.0%
;[.eseg] 0x000000 0x000000      0      0      0     512   0.0%
;
;Assembly complete, 0 errors. 0 warnings




erikc

Attachments

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.