Jump to content

Can DOUT module provide PWM led brightness control?


Lambolico

Recommended Posts

Hello, I'm planning to build a dj midibox controller. I'm just at design's first stage.

I have this quick question which I couldn't answer looking at the web or forums.

Can DOUT module provide PWM led brightness control? Or do I have to use the AOUT module instead of PWM?

Best Regards.

Edited by Lambolico
Link to comment
Share on other sites

I guess it depends of the different levels of intensity you want to get,

but i'm sure you can 'dim' a led pretty easily, with a simple DOUT module, by powering the led at different short intervals.

And in the end it would be much easier than using a AOUT module !

Link to comment
Share on other sites

If it is high enough, it won´t be noticed by the human eye, but certain camcorders/webcams can be affected by it, when both pwm and cam run at fixed "frame" rates, it creates interference, kind of a "moiré effect" over time, hard to explain :)

Link to comment
Share on other sites

If it is high enough, it won´t be noticed by the human eye, but certain camcorders/webcams can be affected by it, when both pwm and cam run at fixed "frame" rates, it creates interference, kind of a "moiré effect" over time, hard to explain :)

Yeah, I know what you mean, but I'm not going to care about how cameras see my midibox :)

On the other hand is this (Next time I'll do my homework better!): http://www.midibox.org/dokuwiki/doku.php?id=questions_and_answers#can_i_use_pwm_to_control_individual_led_brightness

The short answer is that using PWM on DOUT to do individual brightness control on a large number of LEDs is not possible as it would overload the Core.

However, I suppose this was written with the PIC core in mind. Is this also a problem with the LPC17 core?

Thank you all.

Edited by Lambolico
Link to comment
Share on other sites

Interesting! If it was a problem for the old core, it is likely still a problem for the new one and a specialized led driver ic is recommendable - as the processing power has risen, but not by magnitudes....

What I don´t understand is, why are 10khz update rates necessary to achieve "flicker-free" 3 bit pwm brightness?

Say, a human eye regards illuminated->non-illuminated pattern changes with a 100hz refresh rate as flicker-free...

The darkest illumination pattern for 3 bit brightness would be:

on off off off off off off off -> cycle

Then, all eight steps should happen within a 1/100th second timeframe to be perceived as flicker-free.

So, the individual pulse pattern steps should cycle at 800hz, not with 10khz? Without further inspection, I guess this should be possible even on an old Core8...

But me iz probably missing a key point somewhere, maybe someone can enlighten us... :-)

Many greets,

Peter

Edited by Hawkeye
Link to comment
Share on other sites

Yes, it is possible to implement PWM on a Core32 on any number of LED's with absolutely negligible CPU overhead.

In terms of performance, the frequency of PWM is 1/(NumberLevels*DoutPeriod) . With the standard 1ms DOUT refresh rate and 8 brightness levels gives 1/(8*0.001)=125Hz

NumberLevels does not include OFF so this example may be considered as 9 levels.

The method involves a 2 dimensional array: think of it as DoutArray[ PageIndex][LEDIndex]

The DMA interrupt routine simply increments PageIndex 0 to 7each interrupt. The DMA process automagically shifts out the LEDIndex values to the DOUT chain.

Of course when a LED has it's brightness changed there are a number of array accesses executed by the write function. These can be done in a low priority task, however probably not even necessary.

When there is no change there is no CPU load.

With this scheme it is beneficial to used PDM (Pulse Density Modulation) this means distributing the on/offs across the cycle e.g 50% brightness is 0x0x0x0x rather than 000xxxx etc,etc. It results in less possibility of perceptable flicker.

In fact here is the thread that explored this idea. (I have code I can share if anyone is interested)

Edited by Duggle
Link to comment
Share on other sites

Those are good news for me :)

I plan to drive 100-150 leds, no need to extra hardware is nice. I will ask for your code when I get into the software stage.

Thank you all.

If using RGB Leds, I suggest that you experiment with the different value of R,G, and B current limiting resistors before soldering 100's of resistors for LEDs. I think the sensitivity/brightness of the Red, Green, Blue is usually not matched. With, for example, only 8 levels of brightness digitally, it is best if you can normalize the RGB colour balance with the resistors. Basically with all RGB LED's "on" you want to see pure "white"!

I'll post the code to this thread in a day or two. (I don't have access ATM).

Link to comment
Share on other sites

If using RGB Leds, I suggest that you experiment with the different value of R,G, and B current limiting resistors before soldering 100's of resistors for LEDs. I think the sensitivity/brightness of the Red, Green, Blue is usually not matched. With, for example, only 8 levels of brightness digitally, it is best if you can normalize the RGB colour balance with the resistors. Basically with all RGB LED's "on" you want to see pure "white"!

I'll post the code to this thread in a day or two. (I don't have access ATM).

Thanks for the advice! The code will sure be welcome.

Link to comment
Share on other sites

  • 3 weeks later...

(Unfortunately) there are changes to MIOS32 files necessary (albeit minor changes) but allow for compatibility by using mios32_config.h switches:

The modified mios32 files are attached below. I've highlighted the changes in this post for explanation. They consist of dout driver modification (mios32_srio.c,.h) and array access (mios32_dout.c,h). The application specific layer above this e.g void SetLed(u32 LedIndex, u32 Level) is written by you!

#define MIOS32_USE_PAGED_DOUT

#define DOUT_NUM_BUFPAGES 4

This means that 4 pages are used e.g an LED may be off, or have a brightness of 1,2,3 or 4.

In mios_srio.h (file is attahced) the array is declared:

#ifdef MIOS32_USE_PAGED_DOUT

extern volatile u8 mios32_srio_dout_bufpages[DOUT_NUM_BUFPAGES][MIOS32_SRIO_NUM_SR];

#endif

mios32_srio.c (file is attached with this post ) for reference I'll highlight the changes here:

Define two dimensional array:

#ifdef MIOS32_USE_PAGED_DOUT

volatile u8 mios32_srio_dout_bufpages[DOUT_NUM_BUFPAGES][MIOS32_SRIO_NUM_SR];

#endif

...

// inside s32 MIOS32_SRIO_Init(u32 mode) array is initialised:

for(i=0; i<MIOS32_SRIO_NUM_SR; ++i) {

#ifdef MIOS32_USE_PAGED_DOUT

for(j=0;j<DOUT_NUM_BUFPAGES;++j) mios32_srio_dout_bufpages[j]=0;

#endif

mios32_srio_dout = 0x00; // passive state (LEDs off)

mios32_srio_din = 0xff; // passive state (Buttons depressed)

mios32_srio_din_buffer = 0xff; // passive state (Buttons depressed)

mios32_srio_din_changed = 0; // no change

}

Now the guts of it all in s32 MIOS32_SRIO_ScanStart(void *_notify_hook) where the next page is indexed, and it's address loaded into the DMA process:

current_bufpage=(++current_bufpage)%DOUT_NUM_BUFPAGES; //roll through page range

u8 *dout_address = (u8 *)&mios32_srio_dout_bufpages[current_bufpage][0]; //set pointer

// start DMA transfer

MIOS32_SPI_TransferBlock(MIOS32_SRIO_SPI,

dout_address, (u8 *)&mios32_srio_din_buffer[0],

MIOS32_SRIO_NUM_SR,

MIOS32_SRIO_DMA_Callback);

Now in mios32_dout.h the paged array access functions are dedclared (for some reason I included NR (not bit reversed) versions of these functions as well):

extern s32 MIOS32_DOUT_SRSet_Paged(u32 pg, u32 sr, u8 value);

extern s32 MIOS32_DOUT_SRGet_Paged(u32 pg, u32 sr);

extern s32 MIOS32_DOUT_SRSet_Paged_NR(u32 pg, u32 sr, u8 value);

extern s32 MIOS32_DOUT_SRGet_Paged_NR(u32 pg, u32 sr);

The paged array access functions as they appear in mios32_dout.c:

#ifdef MIOS32_USE_PAGED_DOUT

s32 MIOS32_DOUT_SRGet_Paged(u32 pg, u32 sr)

{

// check if SR available

if( sr >= MIOS32_SRIO_NUM_SR )

return -1;

return mios32_dout_reverse_tab[mios32_srio_dout_bufpages[pg][MIOS32_SRIO_NUM_SR - sr - 1]];

}

s32 MIOS32_DOUT_SRSet_Paged(u32 pg, u32 sr, u8 value)

{

// check if SR available

if( sr >= MIOS32_SRIO_NUM_SR )

return -1;

mios32_srio_dout_bufpages[pg][MIOS32_SRIO_NUM_SR - sr - 1]=mios32_dout_reverse_tab[value];

return 0;

}

// NON REVERSED (range check on SR also removed)

s32 MIOS32_DOUT_SRGet_Paged_NR(u32 pg, u32 sr)

{

return mios32_srio_dout_bufpages[pg][MIOS32_SRIO_NUM_SR - sr - 1];

}

s32 MIOS32_DOUT_SRSet_Paged_NR(u32 pg, u32 sr, u8 value)

{

mios32_srio_dout_bufpages[pg][MIOS32_SRIO_NUM_SR - sr - 1]=value;

return 0;

}

#endif

So now the more application specific part you have to write for yourself for example:

void SetLed(u32 LedIndex, u32 Level)

would copy a bit pattern into the pages at LedIndex according to Level.

These routines can be used to drive matrix arrays by having a column/row mask on each page.

This can be combined with PWM/PDM values as well for e.g RGB full colour array!

Please note these modified files need to replace the existing ones. The mios32_config.h config switches mean that other applications will compile and run as before. Take care that you merge any changes (although unlikely) to these mios32 files. Perhaps Thorsten can suggest a better way of managing this?

mios32_srio.h

mios32_srio.c

mios32_dout.h

mios32_dout.c

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...