Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. ;throttle_backemf.asm
  2.  
  3. .NOLIST
  4. ;  ***************************************************************************************
  5. ;  * PWM MODEL RAILROAD THROTTLE                                                          *
  6. ;  *                                                                                      *
  7. ;  * WRITTEN BY:  PHILIP DEVRIES                                                          *
  8. ;  *                                                                                      *
  9. ;  *  Copyright (C) 2003 Philip DeVries                                                   *
  10. ;  *                                                                                      *
  11. ;  *  This program is free software; you can redistribute it and/or modify                *
  12. ;  *  it under the terms of the GNU General Public License as published by                *
  13. ;  *  the Free Software Foundation; either version 2 of the License, or                   *
  14. ;  *  (at your option) any later version.                                                 *
  15. ;  *                                                                                      *
  16. ;  *  This program is distributed in the hope that it will be useful,                     *
  17. ;  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
  18. ;  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                       *
  19. ;  *  GNU General Public License for more details.                                        *
  20. ;  *                                                                                      *
  21. ;  *  You should have received a copy of the GNU General Public License                   *
  22. ;  *  along with this program; if not, write to the Free Software                         *
  23. ;  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA           *
  24. ;  *                                                                                      *
  25. ;  ***************************************************************************************
  26. .LIST
  27.  
  28. .ifdef BACKEMF_ENABLED
  29. ;********************************************************************************
  30. ;* BACKEMF_ADJUST                                                                *
  31. ;* Top level routine                                                             *
  32. ;*                                                                               *
  33. ;* The throttle_set is compared against the back emf generated by the motor      *
  34. ;* and adjusted to reduce the error                                              *
  35. ;*                                                                               *
  36. ;* Inputs:     throttle_set         Target speed                                 *
  37. ;* Returns:    throttle_set         Adjusted target speed                        *
  38. ;* Changed:    error_hi             Adjusted throttle, upper 8 bits (local)      *
  39. ;*             error_lo             Adjusted throttle, lower 8 bits (local)      *
  40. ;*             error_hi_prev        Previous throttle, for filter (global)       *
  41. ;*             error_lo_prev        Previous throttle, for filter (global)       *
  42. ;*             emf_hi               Measured emf, upper 8 bits (local)           *
  43. ;*             emf_lo               Measured emf, lower 8 bits (local)           *
  44. ;*             B_Temp,B_Temp1                                                    *
  45. ;* Calls:      ADC_SETUP_EMF                                                     *  
  46. ;*             div16u                                                            *
  47. ;*             DIVIDE_16_SIMPLE                                                  *
  48. ;* Goto:       none                                                              *
  49. ;********************************************************************************
  50.  
  51.    HILOCAL1    error_lo             ; assign local variables
  52.    HILOCAL2    error_hi
  53.  
  54.    ;*****************************************************************  
  55.    ;*Convert throttle setting into 2 byte 2's compl.                 *
  56.    ;*                                                                *
  57.    ;* This is a 7 bit number plus 1 more bits after the radix        *
  58.    ;* It is in (error_hi) -radix- (error_lo)                         *
  59.    ;*****************************************************************  
  60.    mov   error_hi,throttle_set         ; Put throttle into 16 bit form  
  61.    clr   error_lo
  62.  
  63.    lsr   error_hi                      ; Convert to 2's compliment
  64.    ror   error_lo
  65.  
  66.    ;********************************************************************************
  67.    ;* READ_BACKEMF                                                                  *
  68.    ;* Returns a 2 byte 2's compliment measurement of the motor backemf.             *
  69.    ;*                                                                               *
  70.    ;* 1. Add together 8 samples of the (8 bit) pwm value in the two byte            *
  71.    ;*    emf_hi--emf_lo register.                                                   *
  72.    ;* 2. Multiply by 16.                                                            *
  73.    ;* 3. Result:  Minimum value = 0x000 (decimal 0)                                 *
  74.    ;*             Maximum value = 0x7F8 (decimal 2040)                              *
  75.    ;*                                                                               *
  76.    ;* Time required:                                                                *
  77.    ;* 1. 1st Sample:             125uS                                              *
  78.    ;* 2. next 7 Samples:         455uS                                              *
  79.    ;* 3. balance of Subroutine:  10's of uS                                         *
  80.    ;*    TOTAL                   580uS min                                          *
  81.    ;*                                                                               *
  82.    ;* Each cycle of the 25kHz PWM takes 40uS, therefore, this routine takes         *
  83.    ;* at least 14.5 cycles of the 25kHz pwm.                                        *
  84.    ;*                                                                               *
  85.    ;* Inputs:  None                                                                 *
  86.    ;* Returns: emf_hi--emf_lo:      2 Byte 2's compl (but always positive)          *
  87.    ;*                               measure of motor backemf.                       *
  88.    ;* Changed: B_Temp,B_Temp1                                                       *
  89.    ;* Calls:   ADC_SETUP_EMF                                                        *
  90.    ;********************************************************************************
  91. LOWLOCAL1   emf_hi                     ; Names of local registers
  92. LOWLOCAL2   emf_lo
  93.  
  94. ;READ_BACKEMF:
  95.    rcall ADC_SETUP_EMF                 ; Setup ADC to measure back_emf.
  96.    clr   emf_lo                        ; Clear the value of emf.
  97.    clr   emf_hi
  98.  
  99.    ldi   B_Temp,8                      ; Add 8 samples
  100. WAIT_FOR_EMF_MEASURE:                  ; Wait for a measurement of the EMF
  101.    sbis  ADCSR,ADIF
  102.    rjmp  WAIT_FOR_EMF_MEASURE
  103.    
  104.    in    B_Temp1,ADCH                  ; Read the measurement
  105.  
  106.    sbi   ADCSR,4                       ; Clear the interrupt
  107.  
  108.    add   emf_lo,B_Temp1                ; Add to low byte (no carry)
  109.  
  110.    clr   B_Temp1
  111.    adc   emf_hi,B_Temp1                ; Add carry to high byte.
  112.  
  113.    dec   B_Temp
  114.    brne  WAIT_FOR_EMF_MEASURE          ; Measure for complete set
  115.                                        ; Sum of 8 samples.
  116.  
  117.    ldi   B_Temp,4                      ; Convert 11 bit number into a 15 bit
  118. COMPUTE_EMF_AVERAGE:                   ; number (only 11 significant figures
  119.    lsl   emf_lo                        ; though)
  120.    rol   emf_hi
  121.    dec   B_Temp
  122.    brne  COMPUTE_EMF_AVERAGE
  123.  
  124.    ;*****************************************************************  
  125.    ;* Compute the error.  That is, throttle = throttle - emf         *
  126.    ;*                                                                *  
  127.    ;* The result is a two byte number (signed two's compl) in        *
  128.    ;* error_hi -radix- error_lo                                *
  129.    ;*****************************************************************  
  130.    sub   error_lo,emf_lo               ; subtract low bytes (after radix)
  131.    sbc   error_hi,emf_hi               ; subtract high bytes (before radix)
  132.  
  133. .ifdef   BACKEMF_SCALE_ENABLED
  134.    ;*****************************************************************  
  135.    ;* Error multiplier (complex)                                     *
  136.    ;*                                                                *
  137.    ;* Error gain is equal to:                                        *
  138.    ;*                                                                *
  139.    ;* Error                       err_scale    err_mult              *
  140.    ;* ------------------------ * 2          * 2                      *
  141.    ;*  err_scale                                                     *
  142.    ;* 2         + throttle_set                                       *
  143.    ;*                                                                *
  144.    ;* The maximum gain when throttle_set = 0 is 2^err_mult           *
  145.    ;* is cut in half when throttle_set = 2^err_scale                 *
  146.    ;*                                                                *
  147.    ;* Result is signed two's compliment in                           *
  148.    ;* error_hi--error_lo -radix-                                     *
  149.    ;*****************************************************************  
  150.    cbr   Flags_1,F_negative_err        ; Assume error is positive
  151.      
  152.    sbrs  error_hi,7                    ; Test algebraic sign
  153.    rjmp  POSITIVE_ERR
  154.  
  155.    sbr   Flags_1,F_negative_err        ; If error is negative, set flag.
  156.    com   error_lo                      ; Convert to positive
  157.    com   error_hi
  158.    subi  error_lo,0xFF
  159.    sbci  error_hi,0xFF
  160.  
  161. POSITIVE_ERR:
  162.  
  163.    B_TEMPLOCAL    _bemf_lo_byte
  164.    B_TEMPLOCAL1   _bemf_hi_byte
  165.  
  166.    mov   _bemf_lo_byte,throttle_set    ; Divisor = throttle_set+2^err_scale
  167.    clr   _bemf_hi_byte
  168.    ldi   B_Temp2,EXP2(err_scale)
  169.    add   _bemf_lo_byte,B_Temp2
  170.    adc   _bemf_hi_byte,_bemf_hi_byte
  171.  
  172. ;  mov   dd16uL,error_lo               ; Dividend = error (same register)
  173. ;  mov   dd16uH,error_hi
  174.  
  175.    rcall div16u                        ; Divide error by (throttle+offset)
  176.                                        ; (almost 4 pwm cycles)
  177.                                        ; adds 3 to Cycle_count
  178.  
  179. ;  mov   error_lo,dres16uL             ; Same register
  180. ;  mov   error_hi,dres16uH
  181.  
  182.    sbrs  Flags_1,BF_negative_err       ; Check sign flag
  183.    rjmp  POSITIVE_ERR_1
  184.  
  185.    com   error_lo                      ; Convert back to negative
  186.    com   error_hi                      ; if necessary
  187.    subi  error_lo,0xFF
  188.    sbci  error_hi,0xFF
  189.  
  190. POSITIVE_ERR_1:                        ; Scale for maximum
  191.    ldi   _bemf_lo_byte, 7 - error_mult - err_scale
  192.    rcall DIVIDE_16_SIMPLE
  193.  
  194. .else    ;case BACKEMF_SCALE_ENABLED is NOT enabled
  195.    ;*****************************************************************  
  196.    ;* Error multiplier (simple)                                      *
  197.    ;*                                                                *
  198.    ;* The error multiplier setting (error_mult) can range            *
  199.    ;* from -8 to +7, and the actual error multiplier is              *
  200.    ;* 2^(error_mult), which therefore ranges from 1/256 to 128.      *
  201.    ;*                                                                *
  202.    ;* Step 1.  Multiply by 2^8.                                      *
  203.    ;*          Equivalent to moving the radix point to after         *
  204.    ;*          error_lo.  THIS STEP REQUIRES NO CODE                 *
  205.    ;*                                                                *
  206.    ;* Step 2.  Divide by 2^(error_mult - 8)                          *
  207.    ;*                                                                *
  208.    ;* Result is signed two's compliment in                           *
  209.    ;* error_hi--error_lo -radix-                                     *
  210.    ;*****************************************************************  
  211.  
  212.    ldi   _bemf_lo_byte, 7 - error_mult        
  213.    rcall DIVIDE_16_SIMPLE
  214.  
  215. .endif   ;BACKEMF_SCALE_ENABLED
  216.  
  217.  
  218. COMPUTE_NEW_PWM:
  219.    ;*****************************************************************  
  220.    ;* Add in the original throttle                                   *
  221.    ;*****************************************************************  
  222.    add   error_lo,throttle_set
  223.    clr   B_Temp
  224.    adc   error_hi,B_Temp
  225.  
  226.    ;*****************************************************************
  227.    ;* Clamp to between 0 and +255                                    *
  228.    ;*****************************************************************  
  229.    brmi  SET_ZERO_PWM                  ; If result is NEGATIVE, set to zero.
  230.  
  231.    cpi   error_hi,0x00                 ; If hi byte is zero, result is ok.
  232.    breq  LOWPASS
  233.    ldi   error_lo,0xFF                 ; otherwise, clamp
  234.    rjmp  LOWPASS
  235.  
  236. SET_ZERO_PWM:
  237.    clr   error_lo
  238.  
  239. LOWPASS:
  240.  
  241. .ifdef   LOWPASS_ENABLED
  242.    ;*****************************************************************
  243.    ;* A transversal low pass filter                                  *
  244.    ;* Lowpass on the emf-adjusted pwm                                *
  245.    ;*                                                                *
  246.    ;* gain input "emf_lowpass_gain", range = 0 to 8                  *
  247.    ;*                                                                *
  248.    ;* The actual filter time constant "tau" is equal to              *
  249.    ;* tau = 2^emf_lowpass_gain * sample_interval                     *
  250.    ;*                                                                *
  251.    ;* The sample interval is nominally 10mS, so the time             *
  252.    ;* constant values are:                                           *
  253.    ;* 0    1    2    3    4     5     6     7     8                  *
  254.    ;* 10mS,20mS,40mS,80mS,160mS,320mS,640mS,1.28S,2.56S              *
  255.    ;*                                                                *
  256.    ;* The current sample is added to an attenuated sum of previous   *
  257.    ;* samples as follows:                                            *
  258.    ;*                                                                *
  259.    ;* Adjusted Value = 1/(2^gain) x                                  *
  260.    ;*                   (  1x sample number (i)                      *
  261.    ;*                   +  gain x sample number (i-1)                *
  262.    ;*                   +  gain^2 x sample number (i-2)              *
  263.    ;*                   +  gain^3 x sample number (i-3)              *
  264.    ;*                   + ....                                       *
  265.    ;*                   )                                            *
  266.    ;* Where:                                                         *
  267.    ;* Gain values: gain =  (2^emf_lowpass_gain -  1) / 2^n           *
  268.    ;*                      0,1/2,3/4,7/8,15/16 ... 255/256           *
  269.    ;*                                                                *
  270.    ;* Algorithm:                                                     *
  271.    ;*                                                                *
  272.    ;*    -Input (current sample) in error_lo (error_hi=0)            *
  273.    ;*       0x00FF max                                               *
  274.    ;*                                                                *
  275.    ;*    -Input (scaled sum of previous samples) in                  *
  276.    ;*       error_hi_prev--error_lo_prev.                            *
  277.    ;*       0x00FF * (2^emf_lowpass_gain - 1 ) max                   *
  278.    ;*                                                                *
  279.    ;* 1. The error_hi_prev--error_lo_prev is added to                *
  280.    ;*    error_hi--error_lo                                          *
  281.    ;*       0x00FF * (2^emf_lowpass_gain) max                        *
  282.    ;*                                                                *
  283.    ;* 2. This value is also stored in                                *
  284.    ;*    error_hi_prev--error_lo_prev                                *
  285.    ;*                                                                *
  286.    ;* 3. The value (error_hi--error_lo) is divided by                *
  287.    ;*    2^emf_lowpass_gain (resulting in lowpass value,             *
  288.    ;*    max 0x00FF)                                                 *
  289.    ;*                                                                *
  290.    ;* 4. The value (error_hi--error_lo) is subtracted from           *
  291.    ;*    error_hi_prev--error_lo_prev.  This is the new              *
  292.    ;*    stored value.                                               *    
  293.    ;*****************************************************************  
  294.    clr   error_hi
  295.  
  296.    ;****
  297.    ;* 1. Add in cumulative previous error
  298.    ;****
  299.    add   error_lo,error_lo_prev        ; Add in scaled previous samples
  300.    adc   error_hi,error_hi_prev        ;
  301.  
  302.    ;****
  303.    ;* 2. Store
  304.    ;****
  305.    mov   error_lo_prev,error_lo        ; Store new value
  306.    mov   error_hi_prev,error_hi        ; Store new value
  307.  
  308.    ;****
  309.    ;* 3. Divide new value
  310.    ;****
  311.    ldi   _bemf_lo_byte,emf_lowpass_gain
  312.    rcall DIVIDE_16_SIMPLE
  313.  
  314.    ;****
  315.    ;* 4. New value in error_prev
  316.    ;****
  317. ADJUST_STORED:
  318.    sub   error_lo_prev,error_lo
  319.    sbc   error_hi_prev,error_hi
  320.  
  321. .endif ;LOWPASS_FILTER
  322.  
  323.    mov   throttle_set,error_lo
  324.    subi  Cycle_count,256-15            ; Normal arrival here occurs after 3.5 + 14.5 +
  325.                                        ; pwm cycles.  Add 15 counts here, also 3 added in
  326.                                        ; div16u
  327.  
  328. .endif BACKEMF_ENABLED
  329.