Driving LED dim/glow using PWM pins and MOSFET

stanleyseow
Fri Dec 01, 2017 6:03 am
Hi,

I calculated the red/blue pill have a total of 15 PWM pins and I would like to use ALL of them to drive a 12V LED using a logic level MOSFET…

Is there any restrictions on using ALL the PWM pins using analogWrite ?

Any conflict of timers ?

Thanks

Stanley


RogerClark
Fri Dec 01, 2017 8:53 am
AFIK

As there are only 4 timers on he F103C, you will only be able to output 4 unique PWM values

If you want more than that, you’re probably going to have to do it via an ISR and some code.

There is a good reference for the Maple mini that gives more information on PWM

http://docs.leaflabs.com/static.leaflab … m.html#pwm

Specifically

http://docs.leaflabs.com/static.leaflab … -conflicts


stevestrong
Fri Dec 01, 2017 2:28 pm
I think it is possible to use all channels of a timer but with the same basic frequency for all, different duty cycles are doable though.

stanleyseow
Fri Dec 01, 2017 2:54 pm
I probably only need all the pins to be on 2 unique PWM values only … so does it means I can use all the 15 PWM pins ?

Thanks


RogerClark
Fri Dec 01, 2017 6:37 pm
[stanleyseow – Fri Dec 01, 2017 2:54 pm] –
I probably only need all the pins to be on 2 unique PWM values only … so does it means I can use all the 15 PWM pins ?

Thanks

Can you explain in more detail …


victor_pv
Fri Dec 01, 2017 8:39 pm
There are 4 timers with 4 channels each.
Single frequency per Timer, but each channel can have a different duty cycle as Steve pointed, so you get up to 16 different PWM duty cycles, grouped 4 by 4 in the same frequency.

There is also code in another thread to do PWM by software in any port and any PIN. In that case the frequency is the same for all pins that you drive with the same code, but each can have a different duty cycle. You can use hardware PWM in some pins, and software PWM in others if you want.

If you want to drive multiple leds with just the same PWM frequency and duty, I think it would be a better idea to use a FET, that will allow a much higher load than the MCU. I see you were planning to use a FET already.

So your limitation is just that 4 timers, each can have a certain frequency. 4 channels per timer, each can have a different duty cycle.


RogerClark
Fri Dec 01, 2017 8:50 pm
thanks guys.

I did not I notice the channel setting, but was not sure this would allow the duty cycle to be changed independently.

The leaflabs docs seem to be rather misleading , if it is possible to vary the duty cycle based on a combination of Timer and Channel


stanleyseow
Sat Dec 02, 2017 8:17 am
Here are more details…

I plans to drive a n-channel logic level MOSFET using PWM pins ( either software or hardware ) …

Usually to control the brightness of the LED , in 2 levels … says 30% brightness in some pins and 90% brightness in other pins …

I didn’t knew about the software based PWM to drive any pins… let me search for that and test it out …

Thanks


victor_pv
Sat Dec 02, 2017 2:29 pm
You can use all PWM pins for what you described, since you don’t plan on having a bunch of different frequencies, only duty cycles.
Each of the 15 pins available can have it’s own PWM duty cycle at any given time.
There are 16 pins with timer channels on them, I’m just guessing, without looking at the schematic, that 1 of them may not be usable because it has an input button or something like that, you doublecheck in case you still can use it.

stanleyseow
Tue Dec 05, 2017 9:45 am
Thank you …
I tested it and it is working for the PWM 15 pins with different duty cycle ….

I m using the following MOSFET, IRLZ34N with the following specs for my PWM 12V LED dimm/glow
Vgs(th) – 1-2v,
Rds(on) 35mΩ

BUT when it is fully ON at 3.3V, analogWrite(xx, 255) or digitalWrite(xx,HIGH) the LED is still not at full brightness at 12V. This MOSFET was suppose to be fully open at 2V.

I did a comparison using an Arduino UNO 5V with similar PWM/digitalWrite(HIGH) and the LED is at full brightness at 12V

I tested with other MOSFET IRF530, Vgs(th) – 2-4v, the brightness was even worst …

Any suggested MOSFET should I be using ??

Stanley


stevestrong
Tue Dec 05, 2017 9:48 am
Have you measured the voltage on the output pins for full brightness?

stanleyseow
Tue Dec 05, 2017 3:36 pm
Good idea, will plug into power supply into MOSFET and slowly increase the voltage …
[edited]

I turns on at 3.1V and turn off at 0.9V as per my power supply voltage readings ..


KHODIDAS11
Sat Feb 03, 2018 12:17 pm
please refer datasheets of both mosfets. I think you need to increase gate voltage for turning, this can be observed through your experiment. as arduino uno 5voutput is 5v pulses from pwm and is fed to mosfet gate. while your stm32 runs at 3.3v so you have gpio pulses at 3.3v.

Also as per theory, if you increase gate voltage, then mosfet internal resistance decreases and current flows more.


Pito
Sat Feb 03, 2018 1:04 pm
You need mosfets with 1.0-1.5V threshold (called “logic level” – you have to double check the Vgs(th) in the datasheet). Mind the threshold is not sharp, it is rather a knee (the threshold voltage does not mean the mosfet is fully “on” running the full Ids current). For example Vgs(th) of the BSS223pw (p-channel low power) is typically 0.9V measured at Ids=1.5uA current (datasheet).
Also mind in order to achieve high switching speed you must drive the mosfet with rather higher peak current because of the gate and miller capacitance (based on mosfet type 40pF – 15nF).
When using pwm via the X channels you do not use analogWrite() – see for example viewtopic.php?f=19&t=3037&start=10#p39347

dannyf
Sun Feb 11, 2018 12:47 am


As there are only 4 timers on he F103C, you will only be able to output 4 unique PWM values

The chip itself is much more powerful than that. I don’t have a datasheet handy but tim1..5 eagh has 4 channels. And others with 1 to 2 channels as well. Tim6 and 7 no channels.

So take a look at the datasheet. I haven’t checked the stm32arduino code but I imagine it supports, or can be made to support, all of that.


Wolfie
Mon Feb 12, 2018 9:51 am
Since I’ve been looking at the STM32F4 I’ve been ignoring this forum. But it happens that a few weeks ago I did exactly what you’re looking for.

Originally I had created some Christmas fish bowls that had parallel led strings that were scaling up and down in brightness controlled by a pro-mini, there are six strings each controlled by one of the PWM-capable pins.

Image

Each string’s current can rise to ~150mA and so the controlling pro-mini pin went to the gate of a mosfet (2N7000 200mA max or a BS170 500mA max).

Naturally, I wanted to progress to more strings, and I really like the STM32F103 so that was the obvious next step, but with the following considerations:
1. Can the 3.3V signal effectively control the mosfet rather than the pro-mini 5V signal?

2. Looking at the various pinout images available on the internet, there is some inconsistency about those STM32F103 pins that are PWM capable, and how many there actually are. Can we create a definitive list?

3. I prefer to program and debug the STMF103 using serial, but I note that pins A9 & A10 are denoted as PWM pins for timer 1. Can I still use serial to program and debug without losing two PWM pins?

I am happy to say that, after a while investigating and experimenting, the answers are yes, yes, and, yes.

The mosfets work quite happily with a 3.3V signal.

There are four timers on the STM32F103, each of which has four PWM channels, the default pin allocations are:
TIM1 PA8, PA9, PA10, PA11
TIM2 PA0, PA1, PA2, PA3
TIM3 PA6, PA7, PB0, PB1
TIM4 PB6, PB7, PB8, PB9

Basically, with each time you effectively set the PWM frequency (via the preset and ARR auto-reload register) for its four channels, and then set the duty cycle for each channel. An example later.

Having a look at the STMCube thingy, it shows that, for timer 1, the pins can be reassigned. This is great news for A9 & A10, all we have to do is figure out how to do it in the Arduino IDE. After looking in timer.h (thanks to the guys here for providing this) and correlating this with the STMCube options, much to my surprise, the first thing I tried worked. Very lucky!

Pins A9 & A10 can be redirected to PB14 & PB15 using:
TIMER1_BASE->CCER |= TIMER_CCER_CC2NE | TIMER_CCER_CC3NE

Here’s my TEST setup (obviously I have leds in place of the led strings, but each is controlled by the mosfet, which in turn is controlled by the PWM signal from the STM32F103 pin):

Image

You can see that serial UART1 is connected via A9 & A10. The cable colour corresponds to the timer TIM1=blue, TIM2=grey, TIM3=yellow, TIM4=white.

The colour of the led indicates the channel: red=1, yellow=2, green=3, blue=4.

(NOTE: in a “production” environment I would have a 10k ohm pull-down resistor between the mosfet gate and ground, and a ~470 ohm resistor between the gate and the STM32 pin, both are omitted here. The former keeps the leds off for the small time period when the pins are floating between the power turning on and the MCU starting. Another (better) solution would be to have separate power supplies to the STM32 and the leds, the latter only turning on after the STM is initialised. The 470 ohm resistor is not needed if everythng is working happily, but in the event of a problem at the mosfet / led end, it prevents any undesirable voltage / current getting back to the STM.)

The code (NOTE: when I wrote this I was quite literally “messing about with timers” I did not expect anyone else to see it, and it was simply knocked together to check that each of the sixteen channels could be independently controlled):

struct pin_struct {
uint8_t id;
bool active;
uint8_t timer;
uint8_t channel;
uint16_t intensity;
int8_t increment;
};

pin_struct pins[16];

void setup() {
Serial.begin(115200); // PB10 TX, PB11 RX
delay(500);

TIMER1_BASE->PSC = 72;
TIMER1_BASE->ARR = 1000;
TIMER1_BASE->CCER |= TIMER_CCER_CC2NE | TIMER_CCER_CC3NE;

TIMER2_BASE->PSC = 72;
TIMER2_BASE->ARR = 2000;

TIMER3_BASE->PSC = 72;
TIMER3_BASE->ARR = 3000;

TIMER4_BASE->PSC = 72;
TIMER4_BASE->ARR = 4000;

pins[0] = (pin_struct){PA8, true, 1, 1, 0, 1};
pins[1] = (pin_struct){PB14, true, 1, 2, 500, 1};
pins[2] = (pin_struct){PB15, true, 1, 3, 1000, -1};
pins[3] = (pin_struct){PA11, true, 1, 4, 500, -1};
pins[4] = (pin_struct){PA6, true, 3, 1, 0, 1};
pins[5] = (pin_struct){PA7, true, 3, 2, 1500, 1};
pins[6] = (pin_struct){PB0, true, 3, 3, 3000, -1};
pins[7] = (pin_struct){PB1, true, 3, 4, 1500, -1};
pins[8] = (pin_struct){PB6, true, 4, 1, 0, 1};
pins[9] = (pin_struct){PB7, true, 4, 2, 2000, 1};
pins[10] = (pin_struct){PB8, true, 4, 3, 4000, -1};
pins[11] = (pin_struct){PB9, true, 4, 4, 2000, -1};
pins[12] = (pin_struct){PA0, true, 2, 1, 0, 1};
pins[13] = (pin_struct){PA1, true, 2, 2, 1000, 1};
pins[14] = (pin_struct){PA2, true, 2, 3, 2000, -1};
pins[15] = (pin_struct){PA4, true, 2, 4, 1000, -1};
for (uint8_t i=0; i<16; i++) pinMode(pins[i].id, PWM);
}

void loop() {
timer_gen_reg_map* timer_base;
uint32_t limit;

for (uint8_t i=0; i<16; i++) {

if (pins[i].timer==1) {
limit = TIMER1_BASE->ARR;
}
else {
switch (pins[i].timer) {
case 2: timer_base = TIMER2_BASE; break;
case 3: timer_base = TIMER3_BASE; break;
case 4: timer_base = TIMER4_BASE; break;
}
limit = timer_base->ARR;
}

pins[i].intensity += pins[i].increment;
if (pins[i].intensity+pins[i].increment<0 || pins[i].intensity+pins[i].increment>limit) pins[i].increment = -pins[i].increment;

if (pins[i].timer==1) {
switch (pins[i].channel) {
case 1: TIMER1_BASE->CCR1 = pins[i].intensity;; break;
case 2: TIMER1_BASE->CCR2 = pins[i].intensity;; break;
case 3: TIMER1_BASE->CCR3 = pins[i].intensity;; break;
case 4: TIMER1_BASE->CCR4 = pins[i].intensity;; break;
}
}
else {
switch (pins[i].channel) {
case 1: timer_base->CCR1 = pins[i].intensity;; break;
case 2: timer_base->CCR2 = pins[i].intensity;; break;
case 3: timer_base->CCR3 = pins[i].intensity;; break;
case 4: timer_base->CCR4 = pins[i].intensity;; break;
}
}
}
delay(1);

}


Leave a Reply

Your email address will not be published. Required fields are marked *