Hello, I'd like to use the Pulse Counter (PCNT) to measure the frequency of a square wave on a GPIO Input pin. I found some code that I think will do what I want, but I get an error message when I compile it.
Compilation error: designator order for field 'pcnt_config_t::unit' does not match declaration order in 'pcnt_config_t'
I can't find information that helps me so I thought I'd seek some advice on the forum. Here is the code, any help would be greatly appreciated.
#include <driver/pcnt.h>
#include <driver/dac.h>
#define FREQ_INPUT_PIN 0 // Define the pin for frequency input
#define DAC_OUTPUT_PIN 25 // Define the DAC output pin (GPIO25)
// PCNT unit and channel
#define PCNT_UNIT PCNT_UNIT_0
#define PCNT_CHANNEL PCNT_CHANNEL_0
// Frequency measurement parameters
const int MEASUREMENT_INTERVAL_MS = 1000; // Measurement interval in milliseconds
void setupPulseCounter() {
pcnt_config_t pcnt_config = {
.pulse_gpio_num = FREQ_INPUT_PIN,
.ctrl_gpio_num = PCNT_PIN_NOT_USED,
.channel = PCNT_CHANNEL,
.unit = PCNT_UNIT,
.pos_mode = PCNT_COUNT_INC, // Count rising edges
.neg_mode = PCNT_COUNT_DIS, // Do not count falling edges
.lctrl_mode = PCNT_MODE_KEEP, // Control signal is not used
.hctrl_mode = PCNT_MODE_KEEP, // Control signal is not used
.counter_h_lim = INT16_MAX, // Set high limit
.counter_l_lim = 0 // Set low limit
};
pcnt_unit_config(&pcnt_config);
// Initialize counter value
pcnt_counter_pause(PCNT_UNIT);
pcnt_counter_clear(PCNT_UNIT);
pcnt_counter_resume(PCNT_UNIT);
}
void setup() {
Serial.begin(115200);
pinMode(FREQ_INPUT_PIN, INPUT);
setupPulseCounter();
// Initialize DAC output
dac_output_enable(DAC_CHANNEL_1); // GPIO25 corresponds to DAC channel 1
}
void loop() {
static unsigned long lastTime = 0;
unsigned long currentTime = millis();
if (currentTime - lastTime >= MEASUREMENT_INTERVAL_MS) {
lastTime = currentTime;
int16_t pulse_count = 0;
pcnt_get_counter_value(PCNT_UNIT, &pulse_count);
// Calculate frequency in Hz
float frequency_hz = pulse_count / (MEASUREMENT_INTERVAL_MS / 1000.0);
// Map frequency to analog value (0-255 for 8-bit DAC)
int analog_value = map(frequency_hz, 0, 1000, 0, 255); // Adjust max frequency as needed
analog_value = constrain(analog_value, 0, 255);
// Output analog value
dac_output_voltage(DAC_CHANNEL_1, analog_value);
// Print debugging information
Serial.print("Frequency: ");
Serial.print(frequency_hz);
Serial.print(" Hz, Analog Value: ");
Serial.println(analog_value);
// Reset the pulse counter
pcnt_counter_clear(PCNT_UNIT);
}
}
@rebeljd I never seen that before, did you google the verbatim error msg?
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@RebelJD - Check the order that you have the individual fields listed against the definition of pcnt_config_t (in pcnt.h). Perhaps unit should be used later, or you have the order wrong? I’m just guessing. 😀
@rebeljd
In C, when you initialize a structure using designated initializers (e.g., pcnt_config_t), the fields must appear in the same order as they are defined in the structure declaration. The compiler is checking this and throwing an error because the order in your initializer does not match the declaration order.
A couple ways to fix this are.
If you don’t want to worry about the order, you can initialize the structure without designators: as in
pcnt_config_t config = {0, 1, 2}; // Fields initialized in order
The other way is to make sure the fields are in the same order.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
Yes, that error message was copied from the Arduino IDE. Full disclosure here, this is my first attempt at using Copilot AI to write some code. I do have a need to measure the frequency on a digital input for a project I'm working on and thought I'd give AI a try. The code above was verbatim what it gave me.
I guess I'm not sure where to find the correct order to put things.
I'll be measuring a frequency that will vary from 100khz to 900khz. My thinking was that by using the counter instead of other methods such as interrupts would give better results.
@rebeljd There are two things wrong right off the bat. The code has special characters in it, please only use the <> for code.
Second is your AI doesn't know Arduino C++ so several things are wrong.
You are much better off to look at the library samples, they are created for the Arduino IDE eco system.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
Thanks Ron, that was always my fallback plan - to use a library. Just thought I'd try something new, you never know. Now we do.
Just thought I'd try something new, you never know. Now we do.
Well, I'm not sure we do ... at least fully.
The error message:
Compilation error: designator order for field 'pcnt_config_t::unit' does not match declaration order in 'pcnt_config_t'
indicates the faulty statement
pcnt_config_t pcnt_config = {
.pulse_gpio_num = FREQ_INPUT_PIN,
.ctrl_gpio_num = PCNT_PIN_NOT_USED,
.channel = PCNT_CHANNEL,
.unit = PCNT_UNIT,
.pos_mode = PCNT_COUNT_INC, // Count rising edges
.neg_mode = PCNT_COUNT_DIS, // Do not count falling edges
.lctrl_mode = PCNT_MODE_KEEP, // Control signal is not used
.hctrl_mode = PCNT_MODE_KEEP, // Control signal is not used
.counter_h_lim = INT16_MAX, // Set high limit
.counter_l_lim = 0 // Set low limit
};
The syntax for the struct initialization allows this form. (see: https://en.cppreference.com/w/c/language/struct_initialization, 2nd form)
An example is provided to show such an initialization.
struct {int sec,min,hour,day,mon,year;} z
= {.day=31,12,2014,.sec=30,15,17}; // initializes z to {30,15,17,31,12,2014}
So you can specify the field names out of order.
Syntactically, the statement appears valid but is an edge condition, where the last class member name is used in the middle of the initializer list. Once the compiler encounters the last name it doesn't expect any further names in the initializer list.
The guideline is to use the member declaration in the initializer llst. You can look up the class member declaration order in the pcnt.h file, which should be in the library folder.
The one who has the most fun, wins!
Well obviously AI doesn't know the correct order, that we know.... I rearranged the order and it now compiles without an error.
pcnt_config_t pcnt_config = {
.pulse_gpio_num = FREQ_INPUT_PIN,
.ctrl_gpio_num = PCNT_PIN_NOT_USED,
.lctrl_mode = PCNT_MODE_KEEP, // Control signal is not used
.hctrl_mode = PCNT_MODE_KEEP, // Control signal is not used
.pos_mode = PCNT_COUNT_INC, // Count rising edges
.neg_mode = PCNT_COUNT_DIS, // Do not count falling edges
.counter_h_lim = INT16_MAX, // Set high limit
.counter_l_lim = 0, // Set low limit
.unit = PCNT_UNIT,
.channel = PCNT_CHANNEL,
};
I'm still new to CPP and tend to rely on examples and libraries and sometimes struggle with code I didn't actually write. Now I need to wire this up on the bench and see if it actually works.
Thanks for the help.
Full disclosure here, this is my first attempt at using Copilot AI to write some code.
🙂
Although I didn't post it because I didn't know enough to determine its accuracy out of curiosity I gave your question to chatGPT and got this reply ...
"The compilation error message you are encountering, designator order for field 'pcnt_config_t::unit' does not match declaration order in 'pcnt_config_t', suggests that the designators you're using in the initialization of the pcnt_config_t structure do not follow the order of the fields as they are declared in the struct.
In C and C++, when initializing a structure using designated initializers (the syntax you are using with the dot notation, e.g. .pulse_gpio_num, .unit, etc.), the order in which you specify these fields does not have to match the order in which they are declared in the struct. However, certain compilers may have restrictions or may require specific ordering, especially in older standards of C or C++ or when certain compiler flags are set."
@tfmccarthy Are you going to be another Dave and not read ALL the posts in a topic? I already delivered the information and I was preceded by @yurkshirelad who was the first to make a good guess at what the issue was.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
Are you going to be another Dave and not read ALL the posts in a topic? I already delivered the information and I was preceded by @yurkshirelad who was the first to make a good guess at what the issue was.
That's all very interesting, except, it was inaccurate.
You don't have to use the declaration order. You can specify the members out of order. Did you miss my link to the reference for this with example?
The smallest change should be to move last member name to the end of the initializer list.
pcnt_config_t pcnt_config = {
.pulse_gpio_num = FREQ_INPUT_PIN,
.ctrl_gpio_num = PCNT_PIN_NOT_USED,
.unit = PCNT_UNIT,
.pos_mode = PCNT_COUNT_INC, // Count rising edges
.neg_mode = PCNT_COUNT_DIS, // Do not count falling edges
.lctrl_mode = PCNT_MODE_KEEP, // Control signal is not used
.hctrl_mode = PCNT_MODE_KEEP, // Control signal is not used
.counter_h_lim = INT16_MAX, // Set high limit
.counter_l_lim = 0 , // Set low limit
.channel = PCNT_CHANNEL
};
However, as @robotbuilder noted in his ChatGPT interaction, there may be compiler restrictions, which i described as an "edge condition."
There's more than one answer to this.
Is it really so important to be the first to make a good guess?
Fine, You guessed first.
But I think now we have the full story.
The one who has the most fun, wins!
@tfmccarthy I thought I also mentioned that but perhaps not as it seems contradictory. I did say this but to be 100% honest the words and example seemed to be in conflict but I left it as is
If you don’t want to worry about the order, you can initialize the structure without designators: as in
pcnt_config_t config = {0, 1, 2}; // Fields initialized in order
Not important to be first, but it is important that if you are going to respond that you read the entire thread. You are new and probably unaware of some of the wasted effort that results from incomplete participation.
No, I was not first, as I said, @yurkshirelad was the first to point in the right direction, I simply added a little bit to it.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@tfmccarthy As you know I am autistic so sometimes my language is too direct for neurotypical folks.
You have been here since July, that to me is recent. Not sure how that is off base though, is it like not asking a lady of a certain age her age?
Wow I just saw the definition of condescension. Sorry you feel that way, I am just trying to be informative but I do understand that due to my ASD, I can come across as different from most people.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.