-
Notifications
You must be signed in to change notification settings - Fork 3
No PWM-Output signals #1
Description
Describe the bug
The examples don't work for me out of the box. The interrupts ocur and the LEDs are blinking but i can't see any output at the defined pins.
Steps to Reproduce
Arduino IDE version: 1.8.16
Arduino Portenta H7 REV 2 ABX00042 Bootloader version: 22
OS: Windows 10 Pro
Compiled and flashed any example to the M7 core of the arduino portenta H7.
Expected behavior
Get pwm output signals with the configured frequency and according duty cycles.
Actual behavior
Outputs kept low.
Information
For the example PWM_Multi.ino i had to change the following stuff to get an output signal at Pin D0 (PH15; PWM6):
1: Pin D0(PH15) is not connected to TIM1 but TIM8 (stm32h747xi.pdf Table 7) that's why i changed the first TimerInstance entry.
TIM_TypeDef *TimerInstance[] = { TIM8, TIM5, TIM7, TIM8, TIM12, TIM13, TIM14 };
2: The arduino like pin configuration:
for (uint8_t index = 0; index < NUM_OF_PINS; index++)
{
pinMode(pins[index], OUTPUT);
digitalWrite(pins[index], LOW);
}
doesn't work for me i used the following pin initialization code:
/*Configure GPIO pin : PH15 */
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_15; // Pin15
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Alternate = GPIO_AF3_TIM8; //according to https://www.st.com/resource/en/datasheet/stm32h747xi.pdf Table 15: Port H alternate functions
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
3: It seems like the line:
MyTim[index]->setPWM(channel, pins[index], freq[index], 25, PeriodCallback[index]);
Sets the wrong bits in the TIM8_CCER Register. The problem is, that the CCER Registers of the advanced Timers 1 and 8 differs from the CCER registers 2 to 5. After calling setPWM() the TIM8->CCER register is set to 256 but should be 1024 (according to advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf Chapter 40.4.11).
I added the line Instance->CCER = 1024; after the setPWM() call.
Example
//Arduino IDE version: 1.8.16
//Arduino Portenta H7 REV 2
//OS: WIndows 10 Pro
//Working example:
//Based on:
/****************************************************************************************************************************
PWM_Multi.ino
For Portenta_H7 boards
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/Portenta_H7_PWM
Licensed under MIT license
Now even you use all these new 16 ISR-based timers,with their maximum interval practically unlimited (limited only by
unsigned long miliseconds), you just consume only one Portenta_H7 STM32 timer and avoid conflicting with other cores' tasks.
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
Version: 1.0.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K.Hoang 21/09/2021 Initial coding for Portenta_H7 using ArduinoCore-mbed mbed_portenta core
*****************************************************************************************************************************/
#if !( defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) )
#error For Portenta_H7 only
#endif
#include "Portenta_H7_PWM.h"
#define LED_ON LOW
#define LED_OFF HIGH
//D0, Instance = 0x40010400, channel = 3, TimerIndex = 7
//D1, Instance = 0x40010000, channel = 1, TimerIndex = 0
//D2, Instance = 0x40010000, channel = 2, TimerIndex = 0
//D4, Instance = 0x40000400, channel = 2, TimerIndex = 2
//D5, Instance = 0x40000400, channel = 1, TimerIndex = 2
// A0-A6
//A0/D15, Instance = 0x40010400, channel = 3, TimerIndex = 7
//A1/D16, Instance = 0x40010000, channel = 1, TimerIndex = 0
// Can't use same TimerIndex again, e.g., the D1 and D2 can't be use together as the latter called will override
// That's why D0, D1 and D4 (using TimerIndex 7,0 ans 2) are OK together
// Only OK for D0, D1, D2, D4 and D5, PA_0C(D15/A0), PA_1C(D16/A1),
// D3, D6, D7, D8, D9, D10, D11, D12, D13, D14, D17(PC_2C/A2), D18(PC_3C/3), PC2(D19/A4) LEDG, LEDB not OK
#define pin0 D0
#define pin1 D1
#define pin2 D2 //D2
#define pin3 D4
#define pin4 D5
#define pin5 PA_0C
#define pin6 PA_1C
uint32_t pins[] = { pin0, pin1, pin2, pin3, pin4, pin5, pin6 };
#define NUM_OF_PINS 1//( sizeof(pins) / sizeof(uint32_t) )
uint32_t dutyCycle[] = { 10, 20, 30, 50, 70, 90, 100 };
uint32_t freq[] = { 1, 2, 5, 10, 20, 50, 100 };
//TIM_TypeDef *TimerInstance[] = { TIM8, TIM12, TIM13, TIM14, TIM15, TIM16, TIM17 };
//TIM_TypeDef *TimerInstance[] = { TIM1, TIM4, TIM7, TIM8, TIM12, TIM13, TIM14 };
TIM_TypeDef *TimerInstance[] = { TIM8, TIM4, TIM7, TIM8, TIM12, TIM13, TIM14 };
volatile uint32_t callbackTime[] = { 0, 0, 0, 0, 0, 0, 0 };
//callback_function_t PeriodCallback0()
void PeriodCallback0()
{
static bool ledON = LED_OFF;
callbackTime[0]++;
digitalWrite(LEDG, ledON);
ledON = !ledON;
}
void PeriodCallback1()
{
static bool ledON = LED_OFF;
digitalWrite(LEDB, ledON);
callbackTime[1]++;
ledON = !ledON;
}
void PeriodCallback2()
{
static bool ledON = LED_OFF;
digitalWrite(LEDR, ledON);
callbackTime[2]++;
ledON = !ledON;
}
void PeriodCallback3()
{
callbackTime[3]++;
}
void PeriodCallback4()
{
callbackTime[4]++;
}
void PeriodCallback5()
{
callbackTime[5]++;
}
void PeriodCallback6()
{
callbackTime[6]++;
}
callback_function_t PeriodCallback[] =
{
PeriodCallback0, PeriodCallback1, PeriodCallback2, PeriodCallback3, PeriodCallback4, PeriodCallback5, PeriodCallback6
};
void printLine()
{
Serial.println(F("\n=========================================================================================================="));
}
void printCount()
{
static uint32_t num = 0;
if (num++ % 50 == 0)
{
printLine();
for (uint8_t index = 0; index < NUM_OF_PINS; index++)
{
Serial.print(F("Count ")); Serial.print(index); Serial.print(F("\t\t"));
}
printLine();
}
if (num > 1)
{
for (uint8_t index = 0; index < NUM_OF_PINS; index++)
{
Serial.print(callbackTime[index]); Serial.print(F("\t\t"));
}
Serial.println();
}
}
#define PRINT_INTERVAL 10000L
void check_status()
{
static unsigned long checkstatus_timeout = 0;
// Print every PRINT_INTERVAL (10) seconds.
if ((millis() > checkstatus_timeout) || (checkstatus_timeout == 0))
{
printCount();
checkstatus_timeout = millis() + PRINT_INTERVAL;
}
}
void setup()
{
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
pinMode(LEDR, OUTPUT);
digitalWrite(LEDG, LED_OFF);
digitalWrite(LEDB, LED_OFF);
digitalWrite(LEDR, LED_OFF);
/*for (uint8_t index = 0; index < NUM_OF_PINS; index++)
{
pinMode(pins[index], OUTPUT);
digitalWrite(pins[index], LOW);
}*/
//use this initialization
/*Configure GPIO pin : PH15 */
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_15; // Pin15
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Alternate = GPIO_AF3_TIM8; //according to https://www.st.com/resource/en/datasheet/stm32h747xi.pdf Table 15: Port H alternate functions
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
//
Serial.begin(115200);
while (!Serial);
delay(100);
Serial.print(F("\nStarting PWM_Multi on ")); Serial.println(BOARD_NAME);
Serial.println(PORTENTA_H7_PWM_VERSION);
// Automatically retrieve TIM instance and channel associated to pin
// This is used to be compatible with all STM32 series automatically.
for (uint8_t index = 0; index < NUM_OF_PINS; index++)
{
TIM_TypeDef *Instance = TimerInstance[index];
// Automatically retrieve TIM instance and channel associated to pin
// This is used to be compatible with all STM32 series automatically.
//TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pins[index]), PinMap_PWM);
uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pins[index]), PinMap_PWM));
Serial.print("Index = "); Serial.print(index);
Serial.print(", Instance = 0x");Serial.print( (uint32_t) Instance, HEX);
Serial.print(", channel = ");Serial.print(channel);
Serial.print(", TimerIndex = "); Serial.println(get_timer_index(Instance));
HardwareTimer *MyTim = new HardwareTimer(Instance);
// void HardwareTimer::setPWM(uint32_t channel, PinName pin, uint32_t frequency, uint32_t dutycycle,
// callback_function_t PeriodCallback, callback_function_t CompareCallback)
MyTim->setPWM(channel, pins[index], freq[index], dutyCycle[index], PeriodCallback[index]);
Instance->CCER = 1024;//TIM1 and 8 have other CCER Registers than the other timers
}
}
void loop()
{
check_status();
}