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
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
Thanks
[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 …
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.
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
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
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.
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
[edited]
I turns on at 3.1V and turn off at 0.9V as per my power supply voltage readings ..
Also as per theory, if you increase gate voltage, then mosfet internal resistance decreases and current flows more.
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
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.
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.

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):

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);
}

