Open CloudHead84 opened 1 year ago
This is the ESP32.cpp
#include <stdlib.h>
extern "C" {
#include "openplc.h"
}
#include "Arduino.h"
#include "../examples/Baremetal/defines.h"
#include "ESP32_FastPWM.h"
//OpenPLC HAL for ESP32 boards
/******************PINOUT CONFIGURATION**************************
Digital In: 17, 18, 19, 21, 22, 23, 27, 32 (%IX0.0 - %IX0.7)
33 (%IX1.0 - %IX1.0)
Digital Out: 01, 02, 03, 04, 05, 12, 13, 14 (%QX0.0 - %QX0.7)
15, 16 (%QX1.0 - %QX1.1)
Analog In: 34, 35, 36, 39 (%IW0 - %IW2)
Analog Out: 25, 26 (%QW0 - %QW1)
*****************************************************************/
//Create the I/O pin masks
uint8_t pinMask_DIN[] = {PINMASK_DIN};
uint8_t pinMask_AIN[] = {PINMASK_AIN};
uint8_t pinMask_DOUT[] = {PINMASK_DOUT};
uint8_t pinMask_AOUT[] = {PINMASK_AOUT};
#define NUM_OF_PWM_PINS 8 //only 8 pins possible with independent frequency
#define PWM_CHANNEL_0_PIN 4
#define PWM_CHANNEL_1_PIN 13
#define PWM_CHANNEL_2_PIN 18
#define PWM_CHANNEL_3_PIN 19
#define PWM_CHANNEL_4_PIN 21
#define PWM_CHANNEL_5_PIN 22
#define PWM_CHANNEL_6_PIN 32
#define PWM_CHANNEL_7_PIN 33
#define TIMER_CHANNEL_0 0
#define TIMER_CHANNEL_1 2
#define TIMER_CHANNEL_2 4
#define TIMER_CHANNEL_3 6
#define TIMER_CHANNEL_4 8
#define TIMER_CHANNEL_5 10
#define TIMER_CHANNEL_6 12
#define TIMER_CHANNEL_7 14
float frequency = 1000.0f;
float dutyCycle = 0.0f;
int PWM_resolution = 10;
ESP32_FAST_PWM *PWM_Instance[NUM_OF_PWM_PINS];
const uint8_t pins[] = {PWM_CHANNEL_0_PIN, PWM_CHANNEL_1_PIN, PWM_CHANNEL_2_PIN, PWM_CHANNEL_3_PIN,
PWM_CHANNEL_4_PIN, PWM_CHANNEL_5_PIN, PWM_CHANNEL_6_PIN, PWM_CHANNEL_7_PIN};
const uint8_t timers[] = {TIMER_CHANNEL_0, TIMER_CHANNEL_1, TIMER_CHANNEL_2, TIMER_CHANNEL_3,
TIMER_CHANNEL_4, TIMER_CHANNEL_5, TIMER_CHANNEL_6, TIMER_CHANNEL_7};
extern "C" uint8_t set_hardware_pwm(uint8_t, float, float); //this call is required for the C-based PWM block on the Editor
bool pwm_initialized = false;
void hardwareInit()
{
for (int i = 0; i < NUM_DISCRETE_INPUT; i++)
{
pinMode(pinMask_DIN[i], INPUT);
}
for (int i = 0; i < NUM_ANALOG_INPUT; i++)
{
pinMode(pinMask_AIN[i], INPUT);
}
for (int i = 0; i < NUM_DISCRETE_OUTPUT; i++)
{
pinMode(pinMask_DOUT[i], OUTPUT);
}
for (int i = 0; i < NUM_ANALOG_OUTPUT; i++)
{
pinMode(pinMask_AOUT[i], OUTPUT);
}
}
uint8_t set_hardware_pwm(uint8_t ch, float freq, float duty)
{
if (ch >= NUM_OF_PWM_PINS)
{
return 0;
}
uint8_t pwm_pin = pins[ch];
// Initialize the PWM instance if not already done
if (PWM_Instance[ch] == nullptr)
{
PWM_Instance[ch] = new ESP32_FAST_PWM(pwm_pin, freq, duty, timers[ch], PWM_resolution);
// Disable the pin for other uses as before
}
if (PWM_Instance[ch]->setPWM(pwm_pin, freq, duty))
{
return 1;
}
return 0;
}
void updateInputBuffers()
{
for (int i = 0; i < NUM_DISCRETE_INPUT; i++)
{
if (bool_input[i/8][i%8] != NULL)
*bool_input[i/8][i%8] = digitalRead(pinMask_DIN[i]);
}
for (int i = 0; i < NUM_ANALOG_INPUT; i++)
{
if (int_input[i] != NULL)
*int_input[i] = (analogRead(pinMask_AIN[i]) * 16);
}
}
void updateOutputBuffers()
{
for (int i = 0; i < NUM_DISCRETE_OUTPUT; i++)
{
if (bool_output[i/8][i%8] != NULL)
digitalWrite(pinMask_DOUT[i], *bool_output[i/8][i%8]);
}
for (int i = 0; i < NUM_ANALOG_OUTPUT; i++)
{
if (int_output[i] != NULL)
dacWrite(pinMask_AOUT[i], (*int_output[i] / 256));
}
}
Inadvertently working on this while adding support for the ESP32-S3. Moving over to LEDC from FastPWM. I'm getting issues though because in order to use LEDC's auto-timer allocation, esp32:esp32 >3.0.0 needs to be used, and when switching over to the development branch for that core I just get drowned in compile errors when trying to build a program from within OpenPLC
Esp32_fastPWM is already using ledc timers... Also all other boards are using the fastPWM libs. Would be a shame to deviate from that. Do you need to use this auto-timer allocation?
My example in the comments is working with a esp32 wroom board. Did you try it with the S3?
Might be more appropriate to add comments to the PR I just opened: #106
Esp32_fastPWM is already using ledc timers...
Internally yes, but looking at the GitHub repos it seems that the maintainer of ESP32_fastPWM no longer intends to maintain it. This wouldn't be aproblem if it worked properly, however I found that (at least on my board) it was not able to do a duty cycle of 0% or 100%, which was extremely inconvenient.
Do you need to use this auto-timer allocation?
It helps a lot because it means that we are no longer statically defining mappings of timers and channels. It means that you can use all timers your board has built in, not just the ones defined in esp32.cpp. This in turn allows for the channel fed to the PWM_CONTROLLER block to simply correlate to a pin on your board, instead of ones statically defined in esp32.cpp
Did you try it with the S3?
I was able to verify that there were issues with FastPWM on the S3, however have not been able to debug my LEDC implementation yet because of some funky versioning problems. Went into more detail in the draft PR
Managed to get all the code on my end sorted out, and if you're still looking for a better PWM_CONTROLLER implementation I'd appreciate some testing of the code in my PR. It likely won't merge until 3.0.0 of arduino-esp32 is released, however as far as I've observed it's pretty stable (why I'd appreciate some testing)
Breaking change from a code side is that the CHANNEL of the PWM_CONTROLLER block now directly correlates to the pin you want to do PWM on.
Hi Thiago,
i just realized that the call of a single pwm_controller function block will trigger the creation of all possible PWM_Instances. So all possible pwm pins are reserved for pwm, even if only 1 channel/pin is used.
I did some reading and realised that if a pin is dedicated to a PWM_Instance, it cannot be used for something else. So i think something like this is not needed:
I then played around and ended up with this solution without the
void init_pwm()
functionWith this, only the pins/channels that are used at the PWM-Controller instances are reserved for PWM. All other unused potential pwm pins can be used as digital/analog input/output.
I have carried out tests with different constellations on my ESP32 board. So with different numbers of pwm pins and digital IOs. It seems to work.
Wanna also give it a try?