millwood0 发表于 2010-6-17 09:49:18

Hi-speed software generated PWM

most software PWM generation methods rely on counting the cycle and then decide if a bit needs to be turned on. This approach, when implemented efficiently, can be fairly fast, but its efficiency goes down as the number of independent pwm channels go up. For example, on a 12F675 running at 4Mhz, the fastest 4-ch 256-bit pwm generation is about 3.5ms, per cycle. The issue there is that at each increment of the cycle counter, you have to compare a pwm's pre-determined duty cycle with the cycle counter to decide if a pwm channel should be turned on (or off). each test takes 3 instruction cycles so if you have 4 channels, that's 12 instruction cycles + a few for the overhead, and you are talking about ~15 instruction cycles per cycle count. for a 256-bit pwm, that's a total of 256*15=4000 instruction cycles. or about 4ms on a 4Mhz pic.

obviously, if you need to generate more channels, the cycle time goes up exponentially and making that approach unacceptible for multi-channel output.

the following is a different approach that aims to minimize the cycle time. Rather than testing each cycle count, this approach tests each channel exponentially and produces exponential delays.

so for 256-bit pwm, it makes just 8 comparison per channel, vs. the 256 comparison per channel of the old method.

the result is greatly improved speed.

millwood0 发表于 2010-6-17 09:49:44

here is the code, implemented on a 12F675.

=============code=======================

#include <htc.h>

__CONFIG(MCLRDIS & BORDIS & WDTDIS & PWRTEN & INTIO);

void delay(unsigned char dly_shift) {        //just waste some time
        while (dly_shift--) NOP();
}
       
#define LED                                (1<<0)
#define PWM_PORT                GPIO
#define PWM_DDR                        TRISIO
#define PWM_SET(bits)        PWM_PORT |= (bits)        //set bits on PWM_port
#define PWM_CLR(bits)        PWM_PORT &=~(bits)        //clear bits on PWM_port
#define PWM_FLP(bits)        PWM_PORT ^= (bits)        //flip bits on PWM_port
#define PWM_STROBE(bits)        PWM_SET(bits); PWM_CLR(bits)
#define PWM1                        (1<<1)                                //pwm pin
#define PWM2                        (1<<2)                                //pwm pin
#define PWM3                        (1<<4)                                //pwm pin
#define PWM4                        (1<<5)                                //pwm pin
#define PWM1_DC                        0x01                                //pwm duty cycles
#define PWM2_DC                        0x20
#define PWM3_DC                        0x4f
#define PWM4_DC                        0x2a
//#define PWM_TMR_OFFSET        0x00                                //tmr0 offset. real cycle from offset+error -> 0xff. error is about 4-5
//#define g_pwmCounter        TMR0                                //define g_pwmCounter as timer

//unsigned char g_pwmCounter=0;

void mcu_init(void) {
        ANSEL=0x00;                                        //all pins gpio
        CMCON=0x07;                                        //analog comparators off
        PWM_DDR &=~(LED | PWM1 | PWM2 | PWM3 | PWM4);        //put pwmx into output mode
}

void
main(void)
{
        unsigned char shift;

        mcu_init();                                        //initialize the mcu       

        while(1)
        {
                for (shift=1; shift<(1<<7); shift<<=1) {
                        (PWM1_DC & shift)? PWM_SET(PWM1): PWM_CLR(PWM1);
                        (PWM2_DC & shift)? PWM_SET(PWM2): PWM_CLR(PWM2);
                        (PWM3_DC & shift)? PWM_SET(PWM3): PWM_CLR(PWM3);
                        (PWM4_DC & shift)? PWM_SET(PWM4): PWM_CLR(PWM4);
                        delay(shift);
                }
        }

}

millwood0 发表于 2010-6-17 09:51:59

the cycle time is about 1ms, vs. 4ms for the old approach.

and the cycle time degrades linearly with the number of channels, not exponentially as in the old approach.

here is the simulation in proteus.

enjoy.


http://cache.amobbs.com/bbs_upload782111/files_30/ourdev_562178.PNG
(原文件名:12F675 PWM Shift.PNG)

fzfh1219 发表于 2010-6-17 09:54:28

楼主为啥不用中文呢

millwood0 发表于 2010-6-17 10:30:11

fixed a bug, refined the delay() routine (so it runs faster).

now, it finishes a cycle in 0.6ms!

===========code===================

#include <htc.h>

__CONFIG(MCLRDIS & BORDIS & WDTDIS & PWRTEN & INTIO);

#define delay0                NOP()
#define delay1                delay0; delay0
#define delay2                delay1; delay1
#define delay3                delay2; delay2
#define delay4                delay3; delay3
#define delay5                delay4; delay4
#define delay6                delay5; delay5
#define delay7                delay6; delay6

void delay(unsigned char dly_shift) {        //just waste some time
//        while (dly_shift--) NOP();
        switch (dly_shift) {
                case (1<<0): delay0; break;
                case (1<<1): delay1; break;
                case (1<<2): delay2; break;
                case (1<<3): delay3; break;
                case (1<<4): delay4; break;
                case (1<<5): delay5; break;
                case (1<<6): delay6; break;
                case (1<<7): delay7; break;
        }
}
       
#define LED                                (1<<0)
#define PWM_PORT                GPIO
#define PWM_DDR                        TRISIO
#define PWM_SET(bits)        PWM_PORT |= (bits)        //set bits on PWM_port
#define PWM_CLR(bits)        PWM_PORT &=~(bits)        //clear bits on PWM_port
#define PWM_FLP(bits)        PWM_PORT ^= (bits)        //flip bits on PWM_port
#define PWM_STROBE(bits)        PWM_SET(bits); PWM_CLR(bits)
#define PWM1                        (1<<1)                                //pwm pin
#define PWM2                        (1<<2)                                //pwm pin
#define PWM3                        (1<<4)                                //pwm pin
#define PWM4                        (1<<5)                                //pwm pin
#define PWM1_DC                        0x01                                //pwm duty cycles
#define PWM2_DC                        0x20
#define PWM3_DC                        0x4f
#define PWM4_DC                        0x2a
//#define PWM_TMR_OFFSET        0x00                                //tmr0 offset. real cycle from offset+error -> 0xff. error is about 4-5
//#define g_pwmCounter        TMR0                                //define g_pwmCounter as timer

//unsigned char g_pwmCounter=0;

void mcu_init(void) {
        ANSEL=0x00;                                        //all pins gpio
        CMCON=0x07;                                        //analog comparators off
        PWM_DDR &=~(LED | PWM1 | PWM2 | PWM3 | PWM4);        //put pwmx into output mode
}

void
main(void)
{
        unsigned char shift;

        mcu_init();                                        //initialize the mcu       

        while(1)
        {
                shift=1;
                while ((shift & (1<<7))==0) {
                        (PWM1_DC & shift)? PWM_SET(PWM1): PWM_CLR(PWM1);
                        (PWM2_DC & shift)? PWM_SET(PWM2): PWM_CLR(PWM2);
                        (PWM3_DC & shift)? PWM_SET(PWM3): PWM_CLR(PWM3);
                        (PWM4_DC & shift)? PWM_SET(PWM4): PWM_CLR(PWM4);
                        shift<<=1;
                        delay(shift);
                }
        }

}

tfdsensor 发表于 2010-6-17 10:39:30

回复【3楼】fzfh1219
楼主为啥不用中文呢
-----------------------------------------------------------------------
楼主一直用英文, 中文输入很生疏了. 很多datasheet都是英文.不乐意笑笑走开就是.

millwood0 发表于 2010-6-17 10:58:01

more optimized: now, it produces 8-bit, 4-ch pwm in 0.5ms (2Khz). 4-bit, 4-ch pwm in 0.15ms (7Khz).

this is probably the fastest pwm routine out there.

=========code============

//multi-channel pwm generation
//about 0.5ms per cycle, 8-bit, 4-ch, on a 12F675 @4Mhz
//about 0.15ms per cycle, 4-bit, 4-ch.
#include <htc.h>

__CONFIG(MCLRDIS & BORDIS & WDTDIS & PWRTEN & INTIO);

#define PWM_Resolution                (1<<3)                        //pwm resolution. (1<<3) = 4-bit / 16 steps, (1<<7)=8-bit / 256 steps
#define LED                                (1<<0)
#define PWM_PORT                GPIO
#define PWM_DDR                        TRISIO
#define PWM_SET(bits)        PWM_PORT |= (bits)        //set bits on PWM_port
#define PWM_CLR(bits)        PWM_PORT &=~(bits)        //clear bits on PWM_port
#define PWM_FLP(bits)        PWM_PORT ^= (bits)        //flip bits on PWM_port
#define PWM_STROBE(bits)        PWM_SET(bits); PWM_CLR(bits)
#define PWM1                        (1<<1)                                //pwm pin
#define PWM2                        (1<<2)                                //pwm pin
#define PWM3                        (1<<4)                                //pwm pin
#define PWM4                        (1<<5)                                //pwm pin
#define PWM1_DC                        0x01                                //pwm duty cycles
#define PWM2_DC                        0x02
#define PWM3_DC                        0x0f
#define PWM4_DC                        0x0e
//#define PWM_TMR_OFFSET        0x00                                //tmr0 offset. real cycle from offset+error -> 0xff. error is about 4-5
//#define g_pwmCounter        TMR0                                //define g_pwmCounter as timer

//unsigned char g_pwmCounter=0;

#define delay0                NOP()
#define delay1                delay0; delay0
#define delay2                delay1; delay1
#define delay3                delay2; delay2
#define delay4                delay3; delay3
#define delay5                delay4; delay4
#define delay6                delay5; delay5
#define delay7                delay6; delay6

void delay(unsigned char dly_shift) {        //just waste some time
//        while (dly_shift--) NOP();
        switch (dly_shift) {
                case (1<<0): delay0; break;
                case (1<<1): delay1; break;
                case (1<<2): delay2; break;
                case (1<<3): delay3; break;
                case (1<<4): delay4; break;
                case (1<<5): delay5; break;
                case (1<<6): delay6; break;
                case (1<<7): delay7; break;
        }
}
       
void mcu_init(void) {
        ANSEL=0x00;                                        //all pins gpio
        CMCON=0x07;                                        //analog comparators off
        PWM_DDR &=~(LED | PWM1 | PWM2 | PWM3 | PWM4);        //put pwmx into output mode
}

void
main(void)
{
        unsigned char shift;

        mcu_init();                                        //initialize the mcu       

        while(1)
        {
                shift=1;
                do {
                        (PWM1_DC & shift)? PWM_SET(PWM1): PWM_CLR(PWM1);
                        (PWM2_DC & shift)? PWM_SET(PWM2): PWM_CLR(PWM2);
                        (PWM3_DC & shift)? PWM_SET(PWM3): PWM_CLR(PWM3);
                        (PWM4_DC & shift)? PWM_SET(PWM4): PWM_CLR(PWM4);
                        delay(shift);
                } while (((shift<<=1) & PWM_Resolution)==0);
        }

}

millwood0 发表于 2010-6-17 11:41:02

by inlining the delay() routine, I know get 8-bitx4 pwm in 0.4ms, and 4-bitx4 pwm in 0.12ms.

wow!

armok 发表于 2010-6-17 11:47:59

谢谢。

好资料。

armok 发表于 2010-6-17 11:50:25

回复【3楼】fzfh1219
楼主为啥不用中文呢
-----------------------------------------------------------------------
其实我一直希望“阿莫电子”上班时管理层能使用英文,抛弃中文。我一直都有这个想法与计划。

很快将送3个员工到英文口语培训班。

dreampet 发表于 2010-6-17 11:52:29

It's great !, but we can't do anything else in the main routine :(

cyberjok 发表于 2010-6-17 15:05:58

PWM4_DC 修改会造成信号斗动,一些应用用不了,比如有刷电机!

wallacer 发表于 2010-8-9 00:14:28

回复【6楼】millwood0
-----------------------------------------------------------------------

It's great!

Delong_z 发表于 2010-11-16 09:38:37

LZ, where are you come form? chinese people welcome you!

funnynypd 发表于 2010-11-16 10:14:50

>很快将送3个员工到英文口语培训班

wow. Nice.
Actually you may want to get direct video English training by people from North America.
I heard there are lots of English Training business target to Korea students via Skype video
(Back to the year of 2003, some company in small towns at Wisconsin hiring almost
all personal in town for the online training business).

P.s. Sooner or later the Skype will not be free anymore.

mcuandme 发表于 2010-11-17 12:24:22

软件实现快速PWM

rube 发表于 2010-11-18 11:44:48

mark

AG17 发表于 2010-12-21 21:01:28

mark

gc56198 发表于 2011-2-24 21:58:10

mark

lan_boy008 发表于 2011-2-25 11:51:30

dddddddd

moonspell 发表于 2011-2-25 12:14:00

不过倾向于硬件处理

allen6kid 发表于 2011-4-28 11:59:32

回复【13楼】Delong_z天之蛟龙
-----------------------------------------------------------------------

你这英语说的啊。。。。。。

uoow 发表于 2011-4-30 15:39:03

Hi-speed software generated PWM
你好 速度 软件 生成 PWM

zhangjinxing 发表于 2011-5-1 00:51:34

mark

wpnx 发表于 2011-5-1 10:29:33

mark

JUGG 发表于 2011-6-28 17:03:00

mark

Helloeveryon 发表于 2011-8-19 17:59:24

mark

usingavr 发表于 2011-9-2 09:20:43

mark soft PWM

myhonour 发表于 2011-9-2 14:16:36

mark

renky 发表于 2011-12-6 21:54:56

mark!

omega999 发表于 2011-12-6 22:24:18

hi-speed PWM mark

spacekey 发表于 2011-12-6 23:07:26

remarkable!

fish47 发表于 2011-12-19 19:04:12

米木兄程序风格很好,马克之。

CK_CN 发表于 2011-12-19 21:08:57

为了看懂millwood0兄台的帖子而努力学外语。。。

raxfeer 发表于 2012-4-13 22:15:35

To type this English article is a hard work,isn't it?
By the way,i'm agree armok said quit use Chinese and use English.
I also want to type like LZ,but my English is very poor.
This reply is just a exercise,</smile~>

JQ_Lin 发表于 2012-4-13 22:28:40

Hi-speed software generated PWM
你好 速度 软件 生成 PWM

Hi-speed 竟然译作“你好 速度”,吼一下!

1ongquan 发表于 2012-5-13 19:06:15

#define delay0                NOP()
#define delay1                delay0; delay0
#define delay2                delay1; delay1
#define delay3                delay2; delay2
#define delay4                delay3; delay3
#define delay5                delay4; delay4
#define delay6                delay5; delay5
#define delay7                delay6; delay6


void delay(unsigned char dly_shift) {      //just waste some time
//      while (dly_shift--) NOP();
      switch (dly_shift) {
                case (1<<0): delay0; break;
                case (1<<1): delay1; break;
                case (1<<2): delay2; break;
                case (1<<3): delay3; break;
                case (1<<4): delay4; break;
                case (1<<5): delay5; break;
                case (1<<6): delay6; break;
                case (1<<7): delay7; break;
      }
}
      

技巧真的很强
页: [1]
查看完整版本: Hi-speed software generated PWM