So-net無料ブログ作成
検索選択

6bitで8bit(幾らでも拡張可能)のpwm検証をカルクしました [PWM]

まずは8bitのデータ(最大値は63*4=252と255にならない)

を6bitに変換する、普通に分布するのと、遅れて分布、進んで分布

(直線補間をしているだけ) にしました。

WS000539.JPG

Rrlというのが毎回の出力値で4回で一巡します。

データが早すぎたり遅すぎたりして途中でも計算が終わっていれば値を変えても大きな誤差には成りません。

Nom 4回で誤差が出ません。

以降はnext(誤差)が残ります。

trl 緩やかに変化します。

Avr 少し結果は遅れます。

adv 少し先読みになり結果は進みます。

aladv 現在値に変化分を加えるので大分先読みになり、場合によっては暴れます。

これらの上限下限のリミット問題、演算の最適化など、未だ解決していません。

少し考え方が進歩できました 。
偏差分を加減して織り込むとき商が少数以下でMOD剰余が出るとき
その辺微分を織り込んでやると更に滑らかに変化に追従でき、
(4サイクルで1変換とするとその時に新値を書き込むことで累積誤差はなくなるのですが)
更に偏差が少なく動作できそうです。

今回は8bitを6bitで高速に操作することを考えていますが、
16bitを24bit以上に拡張する用途
(極低速のVCXO操作とか)に応用するが出来ます。


コメント(0) 

不思議なPWM [PWM]

8bitPWMを例として上げますと、(高速仕様とするため、すべて高速PWMで比較します)

大概のPWM周期は基本クロックの(1+N )倍、Nが255として256に成るのですが、

デューティ は0~255の値を取ることが多く、場合によっては1から256だったりします。

tn2313の場合は 0=1パルス 、255=All Hi

16f628aの場合は 0=0パルス 、255=255 (少しは遅れる)

これらを用いてソフトPWMとハードPWMを組み合わせる場合

最小値、最高値を割り引いて計算する必要があります。

これを考慮するとハードPWM6bit、ソフトPWM2bitとすると125KHzが有利です。

プリスケーラ、前置分周器を1として内部8MHzにしますと、

PIC変換周波数=Fosc/(TMR2 Prescale Value)*(PR2+1)*4

PR2は1/4されるので15にしても、CCPレジスタはFoscが使われるので、6bit相当125KHzになり

AVR変換周波数=Fosc/(前置分周器)*(TOP+1)

TOPに63を使用すると6bitになり125KHzです。

==================================================

-- -------------------------------------------------------------------------------------
-- Title: step_pwm.jal    Test program for Software PWM 2 channel, using a stepper
-- Author: Sebastien Lelong, Copyright (c) 2008-2010, all rights reserved.
-- Adapted-by: Joep Suijs
-- Compiler: >=2.4m
--
-- This file is part of jallib (http://jallib.googlecode.com)
-- Released under the BSD license (http://www.opensource.org/licenses/bsd-license.php)
--
-- Description: this sample show how to use PWM in low resolution mode.
-- ...
--
-- This file has been generated from:
-- * board:
-- * test : 16f648a_pwm_soft2.jal
--
-- 16F648a
-- 1 RA2/AN2/VREF         *+Ci2
-- 2 RA3/AN3/CMP1         *+Ci1
-- 3 RA4/T0CKI/CMP2       * Co2
-- 4 RA5/MCLR/VPP         *Vpp
-- 5 VSS                  *Vss
-- 6 RB0/INT              *Pls
-- 7 RB1/RX/DT            *Dir
-- 8 RB2/TX/CK            *NB
-- 9 RB3/CCP1             *SB
--
-- 18 RA1/AN1             *Sw1
-- 17 RA0/AN0             *Sw2
-- 16 RA7/OSC1/CLKIN      *Sw3
-- 15 RA6/OSC2/CLKOUT     * Co1
-- 14 VDD                 *Vdd
-- 13 RB7/T1OSI/PGD       *Pgd
-- 12 RB6/T1OSO/T1CKI/PGC *Pgc
-- 11 RB5                 *NA
-- 10 RB4/PGM             *SA

;@jallib section chipdef
-- chip setup
include 16f648a

--
-- This program assumes a 8 MHz resonator or crystal
pragma target clock 8_000_000 -- oscillator frequency
pragma target OSC INTOSC_NOCLKOUT -- intosc: i/o on ra6/osc2/clkout, i/o on ra7/osc1/clkin
pragma target WDT disabled
pragma target LVP disabled
-- CONFIG (0x2007)
--
-- include cpusel                    -- target PICmicro
 include delay

-- 1 RA2/AN2/VREF         *+Ci2
-- 2 RA3/AN3/CMP1         *+Ci1
-- 3 RA4/T0CKI/CMP2       * Co2
-- 4 RA5/MCLR/VPP         *Vpp
-- 5 VSS                  *Vss
-- 6 RB0/INT              *Pls
-- 7 RB1/RX/DT            *Dir
-- 8 RB2/TX/CK            *NB
-- 9 RB3/CCP1             *SB
--
-- 18 RA1/AN1             *-Ci2
-- 17 RA0/AN0             *-Ci1
-- 16 RA7/OSC1/CLKIN      *Sw
-- 15 RA6/OSC2/CLKOUT     * Co1
-- 14 VDD                 *Vdd
-- 13 RB7/T1OSI/PGD       *Pgd Pwm2
-- 12 RB6/T1OSO/T1CKI/PGC *Pgc Pwm1
-- 11 RB5                 *NA
-- 10 RB4/PGM             *SA

 var bit  NB                is pin_B2
 var bit  SB                is pin_B3
 var bit  NA                is pin_B5
 var bit  SA                is pin_B4
 var bit  Sw                is pin_A7
 var bit  Pwm2              is pin_B7
 var bit  Pwm1              is pin_B6
 var bit  PC1               is pin_A3
 var bit  MC1               is pin_A0
 var bit  PC2               is pin_A2
 var bit  MC2               is pin_A1
 var bit  Co1               is pin_A6
 var bit  Co2               is pin_A4
 var bit  Pls               is pin_B0
 var bit  Dir               is pin_B1

 var bit  NB_direction      is pin_B2_direction
 var bit  SB_direction      is pin_B3_direction
 var bit  NA_direction      is pin_B5_direction
 var bit  SA_direction      is pin_B4_direction
 var bit  Sw_direction      is pin_A7_direction
 var bit  Pwm2_direction    is pin_B7_direction
 var bit  Pwm1_direction    is pin_B6_direction
 var bit  PC1_direction     is pin_A3_direction
 var bit  MC1_direction     is pin_A0_direction
 var bit  PC2_direction     is pin_A2_direction
 var bit  MC2_direction     is pin_A1_direction
 var bit  Co1_direction     is pin_A6_direction
 var bit  Co2_direction     is pin_A4_direction
 var bit  Pls_direction     is pin_B0_direction
 var bit  Dir_direction     is pin_B1_direction

;//
 NB_direction               = output
 SB_direction               = output
 NA_direction               = output
 SA_direction               = output
 Sw_direction               = input
 Pwm2_direction             = output
 Pwm1_direction             = output
 PC1_direction              = input
 MC1_direction              = input
 PC2_direction              = input
 MC2_direction              = input
 Co1_direction              = output
 Co2_direction              = output
 Pls_direction              = input
 Dir_direction              = input

 var byte poat_dat is PORTA
; include tenpmp

 var VOLATILE byte ndat
 var VOLATILE word mdat
 var VOLATILE byte DTSW
 var VOLATILE byte DTSW1
 var VOLATILE byte DTSW2
 var VOLATILE byte sw1_cunt
 var VOLATILE byte sw2_cunt
 var VOLATILE byte SW_FLG
 var VOLATILE byte temp
 var VOLATILE byte sw_dat
 var VOLATILE byte*2 timcnt = 0
; var VOLATILE byte tim_up = 0
 var VOLATILE byte mode = 0
;// sw_in1/GP5/OSC1/CLKIN  --> 2    7 <-- >GP0/ICSPDAT/USB_out
;// sw_in2/      GP4/OSC2  --> 3    6 <--  GP1/ICSPCLK/vse_in VCC_CHK
;// power_sw GP3/MCLR/Vpp< --> 4    5 <-- > GP2/T0CKI/pump_out

 const VOLATILE bit  USB_ou = 0
 const VOLATILE bit  vcc_ch = 1
 const VOLATILE bit  pump_p = 2
 const VOLATILE bit  powr_s = 3
 const VOLATILE bit  sw_i2  = 4
 const VOLATILE bit  sw_i1  = 5
 const VOLATILE bit  sw_f1  = 0
 const VOLATILE bit  sw_f2  = 1
 const VOLATILE bit  tm_f3  = 2


enable_digital_io()

-- Configure PWM
pin_ccp1_direction = output
include pwm6_hardware
pwm_max_resolution(1)
pwm1_on()

var byte pwmreg1 --
var byte pwmreg2 --
var byte newdat1 --
var byte newdat2 --
var byte pwmdat1 --
var byte pwmdat2 --
-- var bit Pwm1 --
-- var bit Pwm2 --
var byte pwmcunt --

pwmreg1 = 0
pwmreg2 = 0
pwmdat1 = 0
pwmdat2 = 0
Pwm1    = 0
Pwm2    = 0
newdat1 = 155
newdat2 = 96
pwmcunt = 0

--procedure identifier is
--pragma interrupt fast
--   pwm1_set_dutycycle(i);
--end procedure

forever loop

--priodcalc
  pwmreg1 = pwmreg1 + newdat1
  pwmdat1 = (pwmreg1 >> 2)
--  pwmreg1 = pwmreg1 - (pwmdat1 << 2)--6BIT_Conversion
  pwmreg1 = pwmreg1 & 0x03 --6BIT_Conversion
  pwmdat2 = pwmreg2 + newdat2
  pwmdat2 = (pwmreg2 >> 2)
--  pwmreg2 = pwmreg2 - (pwmdat2 << 2)--6BIT_Conversion
  pwmreg2 = pwmreg2 & 0x03 --6BIT_Conversion
--priodcalc_end

--pwm_out
  pwmcunt = 64 --(63?)
  while pwmcunt > 0 loop
--LoZ
    if pwmdat1 > 0 then
       Pwm1 = 1
    else;
       Pwm1 = 0
    end if
    if pwmdat2 > 0 then
       Pwm2 = 1
    else;
       Pwm2 = 0
    end if
--HiZ
    if pwmdat1 > 0 then
      pwmdat1 = pwmdat1 - 1
    end if
    if pwmdat2 > 0 then
      pwmdat2 = pwmdat2 - 1
    end if
  pwmcunt = pwmcunt - 1
  end loop
--pwm_out_end
--next_newdat

end loop


============================================================

-- -------------------------------------------------------------------------------------
-- Title: pwm6_hardware.jal  Hardware PWM control
-- Author: Sebastien Lelong, Copyright (C) 2008-2009, all rights reserved.
-- Adapted-by: Albert Faber, Rob Hamerling.
-- Compiler: 2.4l
--
-- This file is part of jallib (http://jallib.googlecode.com)
-- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html)
--
-- Description:
-- Include this library if you want to use the PWM feature of the CCP module(s).
-- This library uses conditional compile to selectively include underlying PWM
-- libraries and number of PWM channels, according to the target PIC configuration.
-- Ex: - 16f88 has 1 PWM channel: including pwm_hardware will prepare PWM
--       for 1 channel (using pwm_ccp1.jal)
--     - 16f877 has 2 PWM channels: including pwm_hardware will prepare PWM
--       for 2 channels (using pwm_ccp1.jal and pwm_ccp2.jal)
--     - etc. for PICs with more CCP modules
-- Note: All used pin_CCPx_directions should be set to output by the application.
-- --
-- With using the PWM hardware a design choice must be made between desired
-- PWM frequency and desired PWM resolution (number of possible PWM steps).
-- Choosing maximum PWM resolution implies a relative low PWM frequency and
-- vice versa: a high frequency limits the number of available PWM steps.
-- The figures are dependent on the target clock speed.
-- Refer to pwm_common, pwm_ccp1, pwm_ccp2 ... etc. documentation to
-- understand how to use these PWM libraries.
--
-- Notes:
-- 1. Because the PWM libraries use conditional compilation and the 'alias'
--    keyword, at least JalV2 compiler version 2.4l is required.
-- 2. These libraries use the pin alias names as declared in Jallib device
--    files since revision 1171, so Jallib release 0.4 is a minimum requirement.
-- 3. Some PICs have extended CCP modules.  These will be handled by these
--    PWM libraries as 'classic' CCP modules.
--

-- ------ Alias ECCPxCON registers --------

-- NOW DONE IN DEVICEFILES


--  Include common variables and procedures
include pwm6_common


--  Include the libraries for all available CCP modules

if (defined(CCP1CON) == true) then
   include pwm_ccp1
end if

if (defined(CCP2CON) == true) then
   include pwm_ccp2
end if

if (defined(CCP3CON) == true) then
   include pwm_ccp3
end if

if (defined(CCP4CON) == true) then
   include pwm_ccp4
end if

if (defined(CCP5CON) == true) then
   include pwm_ccp5
end if

if (defined(CCP6CON) == true) then
   include pwm_ccp6
end if

if (defined(CCP7CON) == true) then
   include pwm_ccp7
end if

if (defined(CCP8CON) == true) then
   include pwm_ccp8
end if

if (defined(CCP9CON) == true) then
   include pwm_ccp9
end if

if (defined(CCP10CON) == true) then
   include pwm_ccp10
end if

===================================================

------------------------------------------------------------

-- Title: pwm6_common.jal  Hardware PWM control, common procedures
-- Author: Stef Mientki, Copyright (C) 2002-2006, all rights reserved.
-- Adapted-by: Sebastien Lelong
-- Compiler: 2.4l
--
-- This file is part of jallib (http://jallib.googlecode.com)
-- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html)
--
-- Description:
-- This lib handles common operations on PWM, regardless the channel number.
-- It is used in combination with one or more pwm_ccp<number> libraries
-- (eg. pwm_ccp1.jal, pwm_ccp2.jal, etc.). These libraries are included
-- automatically dependent of the configuration of the target PIC.
--
-- Notes:
-- This is a heavy refactoring of the original pwm_hardware.jal (Stef's lib).
--
-- ---------------------------------------------------------------------------


-- Shadow of PR2 (value incremented by 1, i.e. value in range 1..256)
var volatile word _pr2_shadow_plus1 = 64           -- value(PR2) + 1
                                                    -- set to max by default

-- Sets all(!) CCP modules for max (6-bits) PWM resolution.
-- While setting maximum resolution, the Timer2 prescaler can be used to adjust
-- frequency to a some extent with the Timer2 parameter value which can be either:
--   * 1 : high frequency
-- --
-- Below a table showing the PWM frequencies for common clock speeds and
-- different Timer2 prescaler values.
-- ------------------------------------------------------------------------
-- ||*Timer2 prescaler* ||  *8MHz*  ||
-- ||    1              ||  125 kHz ||
-- ------------------------------------------------------------------------
-- For PICs with more than one CCP module you should realize that all CCP
-- modules use Timer2 and PR2 for PWM operations. This means that the PWM
-- period (frequency) of all PWM output pins is the same. Only the duty
-- cycle can vary between one and another PWM pin.
-- --
-- Set PWM to maximum resolution (for all PWM pins!).
-- This implies 1 out of 3 specific PWM frequencies, depending on the Timer2
-- prescaler value passed with the call. See examples in the table above,
-- or use the formula in the datasheet to calculate the resulting frequency.
procedure pwm_max_resolution(byte in prescaler) is

   _pr2_shadow_plus1 = 63                      -- for maximum resolution
   PR2 = byte(_pr2_shadow_plus1 - 1)            -- set PR2

   -- set Timer2 prescaler and turn Timer2 on
   if prescaler == 1 then
      T2CON_T2CKPS = 0b00                       -- prescaler 1:1
      T2CON_TMR2ON = TRUE
   else
      T2CON_TMR2ON = FALSE                      -- disable Timer2 (= PWM off!)
   end if

end procedure


-- Sets all(!) CCP modules for a specific PWM frequency.
-- --
-- The minimum and maximum allowed PWM frequencies depend on the clock speed.
-- When specifying a value beyond the limits PWM will not be started.
-- --
-- The chosen frequency may enforce a limit on the PWM resolution (number of steps).
-- The application program should not specify a higher value for the duty cycle
-- than this limit. When exceeding this limit the dutycycle will probably result
-- in a 'weird' value.
-- Only the procedure set_dutycycle_percent() is safe in this case, the other
-- set_dutycycle procedures use absolute values and are not safe!
procedure pwm_set_frequency(dword in freq) is

   _pr2_shadow_plus1 = word(target_clock / freq) / 4

   T2CON = 0b0000_0000                          -- zero pre/postscaler, disable Timer2
   if ((_pr2_shadow_plus1 > 0)  &               -- freq not too high and
       (_pr2_shadow_plus1 <= 4096)) then        -- freq not too low

      if (_pr2_shadow_plus1 <= 256) then
         T2CON_T2CKPS = 0b00                    -- set Timer2 prescaler 1:1
      end if
      PR2 = byte(_pr2_shadow_plus1 - 1)         -- set PR2
      T2CON_TMR2ON = TRUE                       -- enable Timer2

   end if

end procedure


===================================================================-- --

-------------------------------------------------------------------------------------
-- Title: pwm_ccp1.jal  hardware PWM control, dedicated to module CCP1
-- Author: Stef Mientki, Copyright (C) 2002-2006, all rights reserved.
-- Adapted-by: Sebastien Lelong, Rob Hamerling.
-- Compiler: 2.4l
-- Revision: $Revision: 2760 $
--
-- This file is part of jallib (http://jallib.googlecode.com)
-- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html)
--
-- Description:
-- Performs PWM operations on the CCP1 module.
-- This file is automatically included by pwm_hardware.jal
-- when the target PIC has a CCP1 module.
--
-- Notes: 1. This is a heavy refactoring of the original pwm_hardware.jal
--           (Stef's lib)
--        2. Partly rewritten for JalV2 version 2.4l and Jallib revision 1171.
--           Reduced memory occupation. Added procedure for lowres PWM.
--
-- -------------------------------------------------------------------------------------

var byte  _ccpr1l_shadow  = 0                            -- 8 MSbits of duty cycle
var byte  _ccp1con_shadow = 0b0000_0000                  -- shadow
var bit*2 _ccp1con_shadow_dc1b  at _ccp1con_shadow : 4    -- 2 LSbits of duty cycle
var bit*4 _ccp1con_shadow_ccp1m at _ccp1con_shadow : 0    -- mode pattern


-- PWM mode on
-- Restore duty cycle from shadow registers
-- Note: pin_CCP1_direction should be set to output!
procedure pwm1_on() is

   _ccp1con_shadow_ccp1m = 0b1100                    -- set PWM mode
   CCPR1L                = _ccpr1l_shadow            -- restore duty cycle
   CCP1CON               = _ccp1con_shadow           -- activate CCP module

end procedure


-- PWM mode off
-- retain duty cycle setting in shadow registers
procedure pwm1_off() is

   _ccp1con_shadow_ccp1m = 0b0000                    -- set CCP/PWM off
   CCP1CON               = _ccp1con_shadow

end procedure


-- Set dutycycle with 10-bits resolution, allowing 1024 PWM steps.
-- The 'duty' argument is a (max) 10-bits absolute value for the duty cycle:
--  * duty<1:0> are the 2 LSbits
--  * duty<9:2> are the 8 MSbits
-- Allowed range: 0..1023
-- Note: pin_CCP1_direction should be set to output!
procedure pwm1_set_dutycycle_highres(word in duty) is

   if (duty > 1023) then                            -- upper limit
      duty = 1023
   end if
   _ccpr1l_shadow = byte(duty >> 2)
   _ccp1con_shadow_dc1b = byte(duty) & 0b11

   pwm1_on()                                        -- activate PWM

end procedure


-- Set dutycycle with 8-bits resolution allowing 255 PWM steps.
-- The 'duty' argument is the 8-bits absolute value for the duty cycle:
--  * duty<1:0> are the 2 LSbits
--  * duty<7:2> are the 6 MSbits
-- Allowed range: 0..255
-- Beware that steps 256..1023 are not available. In other words
-- the available PWM range is 25% of the highres procedure.
-- This procedure is particularly suitable with higher frequencies
-- whereby the PWM resolution is limited to 256 steps or less!
procedure pwm1_set_dutycycle_lowres(byte in duty) is

   _ccpr1l_shadow = duty >> 2
   _ccp1con_shadow_dc1b = duty & 0b11

   pwm1_on()                                        -- activate PWM

end procedure


-- Set dutycycle for 10-bits resolution but allowing only 255 PWM steps.
-- This procedure is equivalent to pwm1_set_dutycycle_highres(), but
-- the low order 2 bits of the 10-bits duty cycle are set to 0.
-- This means that only every 4th of the available 1023 steps can be selected
-- and consequently max 255 PWM steps are available.
-- This procedure is for user convenience, allowing to specify an 8 bits
-- value for the duty cycle is for many applications satisfactory.
-- Calling this procedure will also activate PWM.
-- Note: pin_CCP1_direction should be set to output!
procedure pwm1_set_dutycycle(byte in duty) is

   pwm1_set_dutycycle_highres(word(duty) << 2)

end procedure


-- Set a percentage duty cycle, allowing max 100 PWM steps.
-- Allowed range: 0..100
-- The duty cycle will be set to the specified percentage of the maximum
-- for the current PWM frequency.
-- Note: The number of available PWM steps can be lower than 100 with
-- (very) high PWM frequencies.
-- Note: pin_CCP1_direction should be set to output!
procedure pwm1_set_percent_dutycycle(byte in percent) is

   var word duty
   if (percent == 0) then
     duty = 0
   elsif (percent >= 100) then
     duty = _pr2_shadow_plus1 - 1
   else
     duty = word(percent) * (_pr2_shadow_plus1 / 4) / 25      -- (factor PR2/100)
   end if
   pwm1_set_dutycycle_highres(duty << 2)

end procedure

==============================================

最高値を252として計算し直すか、キャリーbitを繰り入れて256まで持って行くか思案中です。

AN700にデルタシグマのアプリケーションが載っていました。

アナログコンパレータをFirmware closes loopする部分です。

AN1050やAN1047にも関連した項目が載っていますが、読み解けていません。

 

 

 

続きを読む


コメント(0) 
メッセージを送る

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。