getting "undefined reference to ledc_cb_register" error - callback

I'm trying to use a callback function with the led controller of esp32, however I'm unable to compile the code. I'm not sure if something is missing or the code has errors, as I have a limited understanding of pointers or coding in general.
I'm using the Arduino framework, however when I hover over the ledc_cb_register text, VSCode will popup some more details/definition of this function, so I would expect that it does see the reference to it.
relevant esp32 documentation:
docs.espressif.com
I'm trying to copy the following example, but make it a bit simpler (using only one channel):
github
It seems this example can be compiled on my side too, but this uses espidf framework.
trying the following code (many lines are not shown here for simplicity)
static bool cb_ledc_fade_end_event(const ledc_cb_param_t *param, void *user_arg)
{
portBASE_TYPE taskAwoken = pdFALSE;
if (param->event == LEDC_FADE_END_EVT) {
isFading = false;
}
return (taskAwoken == pdTRUE);
}
[...]
void setup() {
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_HIGH_SPEED_MODE, // timer mode
.duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
.timer_num = LEDC_TIMER_0, // timer index
.freq_hz = LED_frequency, // frequency of PWM signal
.clk_cfg = LEDC_AUTO_CLK, // Auto select the source clock
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ledc_channel_config_t ledc_channel = {
.gpio_num = LED_PIN,
.speed_mode = LEDC_HIGH_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER_0,
.duty = 4000,
.hpoint = 0,
//.flags.output_invert = 0
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
ledc_fade_func_install(0);
ledc_cbs_t callbacks = {
.fade_cb = cb_ledc_fade_end_event
};
ledc_cb_register(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, &callbacks, 0);
and getting the following error message:
[..]/.platformio/packages/toolchain-xtensa-esp32#8.4.0+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: .pio\build\esp32dev\src\main.cpp.o:(.literal._Z5setupv+0x78): undefined reference to 'ledc_cb_register(ledc_mode_t, ledc_channel_t, ledc_cbs_t*, void*)'
[..]/.platformio/packages/toolchain-xtensa-esp32#8.4.0+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: .pio\build\esp32dev\src\main.cpp.o: in function 'setup()':
[..]\PlatformIO\Projects\asdf/src/main.cpp:272: undefined reference to 'ledc_cb_register(ledc_mode_t, ledc_channel_t, ledc_cbs_t*, void*)'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\esp32dev\firmware.elf] Error 1

According to the docs, it seems to be a feature that was added in v4.4.4
but the latest Arduino core (2.0.6) is build on v4.4.3.
If you are not on the latest Arduino core, try updating that first and see if it works. If not, then you just have to wait until the Arduino core is updated to use ESP IDF v4.4.4.
Of course, you can use ledc_isr_register(...) to register an ISR handler for the interrupt.
Best of luck!
Update:
I realized that the problem (at least on my side when testing it) was that there is an error in the ledc.h file, where they forgot to add ledc_cb_register in an extern "C" block.
I manually patched it by moving the
#ifdef __cplusplus
}
#endif
part, which was located after the ledc_set_fade_step_and_start function, below ledc_cb_register instead.
So, the end of my ledc.h file looks like this now:
...
esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num, ledc_fade_mode_t fade_mode);
/**
* #brief LEDC callback registration function
* ...
*/
esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg);
#ifdef __cplusplus
}
#endif

Related

Emonlib+ADS1115+ESP32+Arduino Function Pointer

I have tried to contact the original designer for the ADS1115->EmonLib adaptation, but unfortunately his Github page has no contact information. I have also tried asking on the OpenEnergyMonitor forum and I get "Contact the person who made the changes".
So, I've come here in the hopes that the knowledgeable folk here can help me out.
Situation:
I have an ESP32 that I'm going to be using to monitor my energy consumption of my home. Because I will be monitoring several circuits I need lots of sensors. The ESP32 only has a 12-bit ADC and I'm limited to only a few sensors. Also limits future expansion if needed.
So here comes the ADS1115, which is a 16-bit ADC, but it uses I2C. Unfortunately, the EmonLib was designed to use onboard ADC, and not through an I2C device. So after doing some digging around, I found this modification to allow the ADS1115 to be used:
https://github.com/PaulWieland/EmonLib/
However, Paul Wieland is not able to be contacted through github.
Ok, so if I wanted to use only 1 ADS1115, I could just use his code as stock, which is this:
// In this example we will use an ADS1115 breakout board instead of the Arduino's local analog inputs
// This is especially useful for nodemcu/esp8266 users who only have a single analog input
#include <Wire.h>
#include <Adafruit_ADS1015.h>
// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3
#include <EmonLib_I2C.h> // Include Emon Library
EnergyMonitor emon1; // Create an instance
Adafruit_ADS1115 ads; // Create an instance of the ADS1115 object
// Make a callback method for reading the pin value from the ADS instance
int ads1115PinReader(int _pin){
return ads.readADC_SingleEnded(_pin);
}
void setup()
{
emon1.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
emon1.current(1, 111.1); // Current: input pin, calibration.
}
void loop()
{
double Irms = emon1.calcIrms(1480); // Calculate Irms only
Serial.print(Irms*230.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms
}
This compiles just fine. Though I am kinda confused as to how to select the "pin" of the ADS.
In the emonlib.cpp he added this code:
//--------------------------------------------------------------------------------------
// Constructor. Set the pinReader to the default pin reader method
//--------------------------------------------------------------------------------------
EnergyMonitor::EnergyMonitor()
{
this->inputPinReader = defaultInputPinReader;
}
//--------------------------------------------------------------------------------------
// By default we just call Arduino's analogRead
//--------------------------------------------------------------------------------------
int EnergyMonitor::defaultInputPinReader(int _pin)
{
return analogRead(_pin);
}
And changed this:
startV = analogRead(inPinV);
to:
startV = (this->inputPinReader)(inPinV);
and a few other spots where he made the adjustment using "this->".
And in the emonlib.h he added this to the Public section:
EnergyMonitor();
typedef int (*inputPinReaderMethod) (int _pin);
inputPinReaderMethod inputPinReader;
static int defaultInputPinReader(int _pin);
Now, for a single ADS1115, I think this works. At least the code compiles. But I need to use 4 ADS1115's as I'll need to be able to monitor up to 16 circuits. I can't for the life of me figure out how to add an array of ADS's to an array of emonlib's.
I tried doing this:
EnergyMonitor emon1[4]; // Create an instance
Adafruit_ADS1115 ads[4]; // Create an instance of the ADS1115 object
// Make a callback method for reading the pin value from the ADS instance
int ads1115PinReader(int _channel, int _pin){
return ads[1].readADC_SingleEnded(_pin);
}
void setup()
{
emon1[1].inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
emon1[1].current(1, 111.1); // Current: input pin, calibration.
}
void loop()
{
double Irms = emon1[1].calcIrms(1480); // Calculate Irms only
Serial.print(Irms*230.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms
}
but then I get this error:
Emon_ADS_Test:18:27: error: invalid conversion from 'int (*)(int, int)' to 'EnergyMonitor::inputPinReaderMethod {aka int (*)(int)}' [-fpermissive]
emon1[1].inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
I'm not very advanced in coding, and function pointers just confuse the heck outta me.
So my dilemma is I have several ADS1115's I need to match to the several instances of the EmonLib.
There has to be a separate instance for each wire monitored. On my working model that uses an Arduino Nano I have 2 emonlib variables (emon1, emon2). This works fine as it uses the internal ADC, tho I've found out over time that it is not very accurate and not fast enough or high enough resolution for my needs. (ie. when 0-current is flowing, it shows 50W usage).
What do I need to make a change to make this thing work?
Kori
[UPDATE 1]
Ok, after some testing, I do still get this:
emon[i * j].inputPinReader = ads1115PinReader;
emon[i * j].current(j++, 111.1);
Unfortunately this throws an error still:
Emon_ADS_Test:21:33: error: invalid conversion from 'int (*)(int, int)' to 'EnergyMonitor::inputPinReaderMethod {aka int (*)(int)}' [-fpermissive]
emon1[i * j].inputPinReader = ads1115PinReader;
However, it comes to the function pointer as being a problem.
I use this code:
int ads1115PinReader(int _pin){
return ads.readADC_SingleEnded(_pin);
}
It works just fine. However if I do this:
int ads1115PinReader(int _channel, int _pin){
return ads[_channel].readADC_SingleEnded(_pin);
}
I get the error above. In the EmonLib_I2C library, the only thing I can think of is in this part:
typedef int (*inputPinReaderMethod) (int _pin);
inputPinReaderMethod inputPinReader;
static int defaultInputPinReader(int _pin);
not matching up. But even that doesn't make sense. In this line:
emon.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
does that mean that when I call inputPinReader, it "actually" grabs the value from ads1115PinReader instead of the one in the library?

STM32 Keil - Can not access target while debugging (AT Command UART)

I am trying to communicate with GSM module via UART communication. I could get message from the module as I expected. However when it comes to while loop (it is empty), debug session ends with "can not access target" error. Stepo by step, I am going to share my code:
Function 1 is AT_Send. (Note: Some of variables are declared globally.)
int AT_Send(UART_HandleTypeDef *huart, ATHandleTypedef *hat, unsigned char *sendBuffer, uint8_t ssize, unsigned char *responseBuffer, uint8_t rsize) {
if (HAL_UART_Transmit_IT(huart,sendBuffer,ssize) != HAL_OK) {
return -1;
}
while ((HAL_UART_GetState(huart) & HAL_UART_STATE_BUSY_TX) == HAL_UART_STATE_BUSY_TX) {
continue;
}
//;HAL_Delay(1000);
if (strstr((char*)receiveBuffer,(char*)responseBuffer) != NULL) {
rxIndex = 0;
memset(command, 0, sizeof(command));
return 0;
}
rxIndex = 0;
memset(command, 0, sizeof(command));
return 1;
}
Second function is AT_Init function. It sends AT to get OK response. At this point on, if I am not wrong, I am opening receive interrrupt and I am trying to get 1 byte.
int AT_Init(UART_HandleTypeDef *huart, ATHandleTypedef *hat)
{
HAL_UART_Receive_IT(huart,&rData,1);
tx = AT_Send(huart,hat,"AT\r",sizeof("AT\r\n"),"OK\r\n",sizeof("OK\r\n"));
return tx;
}
After these two functions, I am calling receive IT function in the call back while there are data on the bus.
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1){
command[rxIndex] = rData;
rxIndex++;
if((rxIndex == 2) && (strstr((char*)command,"\r\n") != NULL)) {
rxIndex = 0;
} else if (strstr((char*)command,"\r\n") != NULL) {
memcpy(receiveBuffer, command, sizeof(command));
rxIndex = 0;
memset(command,0,sizeof(command));
}
HAL_UART_Receive_IT(&huart1,&rData,1);
}
}
Moreover, I am going to send a few HTTP commands simultaneously if I can get rid of this problem.
Can anyone share his/her knowledge?
Edit: Main function is shown below
tx = AT_Init(&huart1,&hat);
while (1)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_3);
HAL_Delay(500);
}
Edit 2: I had replaced uart channel by USART2, and debugger worked. I suppose that it is related to hardware. Still, I am curious about possible reasons that cause to this problem.
The question doesn't mention on which µC the program is running, I only see the "stm32" tag. Similarly, we don't know which debug protocol is used (JTAG or SWD?).
Still, I dare to guess that the toggle command for GPIO port PB3 in the main loop is causing the observations: On many (most? all?) STM32 controllers, PB3 is used as JTDO pin, which is needed for JTAG debug connections.
Please make sure to configure the debug connection to SWD (without SWO, i.e., neither SWV is correct). It may also help to check the wiring of the debug cable, the fast toggle at the PB3/JTDO line may influence the signal levels on some neighbouring SWD lines if the wiring is low quality or a fast SWD speed has been chosen.
My hypothesis can be falsified by removing all actions to PB3. If the problem remains, I'm wrong.

std::lock_guard (mutex) produces deadlock

First: Thanks for reading this question and tryin' to help me out. I'm new to the whole threading topic and I'm facing a serious mutex deadlock bug right now.
Short introduction:
I wrote a game engine a few months ago, which works perfectly and is being used in games already. This engine is based on SDL2. I wanted to improve my code by making it thread safe, which would be very useful to increase performance or to play around with some other theoretical concepts.
The problem:
The game uses internal game stages to display different states of a game, like displaying the menu, or displaying other parts of the game. When entering the "Asteroid Game"-stage I recieve an exception, which is thrown by the std::lock_guard constructor call.
The problem in detail:
When entering the "Asteroid Game"-stage a modelGetDirection() function is being called to recieve a direction vector of a model. This function uses a lock_guard to make this function being thread safe. When debugging this code section this is where the exception is thrown. The program would enter this lock_guard constructor and would throw an exception. The odd thing is, that this function is NEVER being called before. This is the first time this function is being called and every test run would crash right here!
this is where the debugger would stop in threadx:
inline int _Mtx_lockX(_Mtx_t _Mtx)
{ // throw exception on failure
return (_Check_C_return(_Mtx_lock(_Mtx)));
}
And here are the actual code snippets which I think are important:
mutex struct:
struct LEMutexModel
{
// of course there are more mutexes inside here
mutex modelGetDirection;
};
engine class:
typedef class LEMoon
{
private:
LEMutexModel mtxModel;
// other mutexes, attributes, methods and so on
public:
glm::vec2 modelGetDirection(uint32_t, uint32_t);
// other methods
} *LEMoonInstance;
modelGetDirection() (engine)function definition:
glm::vec2 LEMoon::modelGetDirection(uint32_t id, uint32_t idDirection)
{
lock_guard<mutex> lockA(this->mtxModel.modelGetDirection);
glm::vec2 direction = {0.0f, 0.0f};
LEModel * pElem = this->modelGet(id);
if(pElem == nullptr)
{pElem = this->modelGetFromBuffer(id);}
if(pElem != nullptr)
{direction = pElem->pModel->mdlGetDirection(idDirection);}
else
{
#ifdef LE_DEBUG
char * pErrorString = new char[256 + 1];
sprintf(pErrorString, "LEMoon::modelGetDirection(%u)\n\n", id);
this->printErrorDialog(LE_MDL_NOEXIST, pErrorString);
delete [] pErrorString;
#endif
}
return direction;
}
this is the game function that uses the modelGetDirection method! This function would control a space ship:
void Game::level1ControlShip(void * pointer, bool controlAble)
{
Parameter param = (Parameter) pointer;
static glm::vec2 currentSpeedLeft = {0.0f, 0.0f};
glm::vec2 speedLeft = param->engine->modelGetDirection(MODEL_VERA, LEFT);
static const double INCREASE_SPEED_LEFT = (1.0f / VERA_INCREASE_LEFT) * speedLeft.x * (-1.0f);
// ... more code, I think that's not important
}
So as mentioned before: When entering the level1ControlShip() function, the programm will enter the modelGetDirection() function. When entering the modelGetDirection() function an exception will be thrown when tryin' to call:
lock_guard<mutex> lockA(this->mtxModel.modelGetDirection);
And as mentioned, this is the first call of this function in the whole application run!
So why is that? I appreciate any help here! The whole engine (not the game) is an open source project and can be found on gitHub in case I forgot some important code snippets (sorry! in that case):
GitHub: Lynar Moon Engine
Thanks for your help!
Greetings,
Patrick

As to the GPIOTE function(External Interrupt) of nRF52832

I have some trouble to control GPIOTE function with nRF52832 sdk,
when using 14.01 version(SDK), it seems that the GPIOTE function can't be used with BLE function, I used the code below, it made hang-up issue of system, why?
I wonder whether GPIOTE function can't be used with BLE function or not,
and another method to use the function with BLE function,
thankful for your support and kindness in advance,
#define PIN_IN BUTTON_4
//#define PIN_OUT BSP_LED_3
void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
printf("love %d: %d\n", (int)pin, (int)action);
// nrf_drv_gpiote_out_toggle(PIN_OUT);
}
/**
* #brief Function for configuring: PIN_IN pin for input, PIN_OUT pin for output,
* and configures GPIOTE to give an interrupt on pin change.
*/
void gpio_external_int_init(void)//love_1108
{
uint32_t err_code;
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
//
err_code = nrf_drv_gpiote_init();
APP_ERROR_CHECK(err_code);
//
// (void)nrf_drv_gpiote_init();
// nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);
// err_code = nrf_drv_gpiote_out_init(PIN_OUT, &out_config);
// APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
in_config.pull = NRF_GPIO_PIN_PULLUP;
err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_in_event_enable(PIN_IN, true);
}
While you don't provide much detail, such as what is meant by "used with BLE function", I have found an issue with the SDK example ble_app_template. In my case the cause was that the file bsp_btn_ble.c demands that there are more buttons than my board_custom.h defines. So the function startup_event_extract() wants to check the state of BTN_ID_WAKEUP_BOND_DELETE, which does not exist on my hardware, causes an assertion. It is disturbing that BTN_ID_WAKEUP_BOND_DELETE and other buttons are defined in the c file, rather than being derived from custom_board.h.
So, trace the board initialization and you may find something like ASSERT(button_idx < BUTTONS_NUMBER), which caused a hang in my case.

Page fault with newlib functions

I've been porting newlib to my very small kernel, and I'm stumped: whenever I include a function that references a system call, my program will page fault on execution. If I call a function that does not reference a system call, like rand(), nothing will go wrong.
Note: By include, I mean as long as the function, e.g. printf() or fopen(), is somewhere inside the program, even if it isn't called through main().
I've had this problem for quite some time now, and have no idea what could be causing this:
I've rebuilt newlib numerous times
Modified my ELF loader to load the
code from the section headers instead of program headers
Attempted to build newlib/libgloss separately (which failed)
Linked the libraries (libc, libnosys) through the ld script using GROUP, gcc and ld
I'm not quite sure what other information I should include with this, but I'd be happy to include what I can.
Edit: To verify, the page faults occurring are not at the addresses of the failing functions; they are elsewhere in the program. For example, when I call fopen(), located at 0x08048170, I will page fault at 0xA00A316C.
Edit 2:
Relevant code for loading ELF:
int krun(u8int *name) {
int fd = kopen(name);
Elf32_Ehdr *ehdr = kmalloc(sizeof(Elf32_Ehdr*));
read(fd, ehdr, sizeof(Elf32_Ehdr));
if (ehdr->e_ident[0] != 0x7F || ehdr->e_ident[1] != 'E' || ehdr->e_ident[2] != 'L' || ehdr->e_ident[3] != 'F') {
kfree(ehdr);
return -1;
}
int pheaders = ehdr->e_phnum;
int phoff = ehdr->e_phoff;
int phsize = ehdr->e_phentsize;
int sheaders = ehdr->e_shnum;
int shoff = ehdr->e_shoff;
int shsize = ehdr->e_shentsize;
for (int i = 0; i < pheaders; i++) {
lseek(fd, phoff + phsize * i, SEEK_SET);
Elf32_Phdr *phdr = kmalloc(sizeof(Elf32_Phdr*));
read(fd, phdr, sizeof(Elf32_Phdr));
u32int page = PMMAllocPage();
int flags = 0;
if (phdr->p_flags & PF_R) flags |= PAGE_PRESENT;
if (phdr->p_flags & PF_W) flags |= PAGE_WRITE;
int pages = (phdr->p_memsz / 0x1000) + 1;
while (pages >= 0) {
u32int mapaddr = (phdr->p_vaddr + (pages * 0x1000)) & 0xFFFFF000;
map(mapaddr, page, flags | PAGE_USER);
pages--;
}
lseek(fd, phdr->p_offset, SEEK_SET);
read(fd, (void *)phdr->p_vaddr, phdr->p_filesz);
kfree(phdr);
}
// Removed: code block that zeroes .bss: it's already zeroed whenever I check it anyways
// Removed: code block that creates thread and adds it to scheduler
kfree(ehdr);
return 0;
}
Edit 3: I've noticed that if I call a system call, such as write(), and then call printf() two or more times, I will get an unknown opcode interrupt. Odd.
Whoops! Figured it out: when I map the virtual address, I should allocate a new page each time, like so:
map(mapaddr, PMMAllocPage(), flags | PAGE_USER);
Now it works fine.
For those curious as to why it didn't work: when I wasn't including printf(), the size of the program was under 0x1000 bytes, so mapping with only one page was okay. When I include printf() or fopen(), the size of the program was much bigger so that's what caused the issue.