I am currently using "STM32F429I-DISC1" with joystick. I am trying to draw something on the LCD screen and using joystick move this object. My drawing is working fine, but I have the error: " void value not ignored as it ought to be".
This two lines have problems...
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4);
Can someone please tell me, how I can fix this error?
And why I see this error?
Main.c
#include "stm32f429i_discovery_lcd.h"
#define CTRL_REG_IN3 0b00011000
#define CTRL_REG_IN4 0b00100000
SemaphoreHandle_t xMutex;
Joystick_data xy;
void vTaskFunction1(void *pvParameters) {
uint16_t localX;
uint16_t localY;
for(;;) {
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4);
xSemaphoreTake( xMutex, portMAX_DELAY );
xy.x = localX;
xy.y = localY;
xSemaphoreGive( xMutex );
HAL_Delay(10);
}
}
void vTaskFunction2(void *pvParameters) {
uint32_t xCoord = 240/2;
uint32_t yCoord = 320/2;
uint8_t reads = 0;
uint8_t ballRadius = 5;
uint16_t xLimitMin = ballRadius+25;
uint16_t xLimitMax = 240-ballRadius-25;
uint16_t yLimitMin = ballRadius+25;
uint16_t yLimitMax = 320-ballRadius-25;
for(;;) {
xSemaphoreTake( xMutex, portMAX_DELAY );
if (xy.x > 3000 && !(xCoord < xLimitMin))
xCoord -= 5;
if (xy.x < 1000 && !(xCoord > xLimitMax))
xCoord += 5;
if (xy.y > 3000 && !(yCoord < yLimitMin))
yCoord -= 5;
if (xy.y < 1000 && !(yCoord > yLimitMax))
yCoord += 5;
reads++;
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_DrawCircle(xCoord, yCoord, ballRadius);
BSP_LCD_FillCircle(xCoord, yCoord, ballRadius);
xSemaphoreGive(xMutex);
HAL_Delay(20);
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI4_Init();
MX_TIM1_Init();
MX_USART1_UART_Init();
// LCD Things
BSP_LCD_Init();
BSP_LCD_LayerDefaultInit(1, LCD_FRAME_BUFFER);
BSP_LCD_SelectLayer(1);
BSP_LCD_SetBackColor(LCD_COLOR_WHITE); // Vali meelepärane värv
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_SetTextColor(LCD_COLOR_DARKBLUE); // Vali meelepärane värv
MX_FREERTOS_Init();
if ( xMutex == NULL )
{
xMutex = xSemaphoreCreateMutex();
if ( ( xMutex ) != NULL )
xSemaphoreGive( ( xMutex ) );
}
xTaskCreate(vTaskFunction1, "Task 1", 100, NULL, 1, NULL);
xTaskCreate(vTaskFunction2, "Task 2", 100, NULL, 1, NULL);
vTaskStartScheduler();
osKernelStart();
while (1)
{
}
}
Read joystick function (joystick.c)
#include <stdio.h>
#include <main.h>
#include "gpio.h"
#include "spi.h"
#define READ_SLAVE_OPERATION 0b10000000
#define READ_INCR_SLAVE_OPERATION 0b11000000
#define WRITE_SLAVE_OPERATION 0b00000000
#define CTRL_REG_IN3 0b00000011
#define CTRL_REG_IN4 0b00000100
#define OUT_X_L 0x28
#define OUT_X_H 0x29
#define OUT_Y_L 0x2A
#define OUT_Y_H 0x2B
#define OUT_Z_L 0x2C
#define OUT_Z_H 0x2D
#define JOY_CS_LOW() HAL_GPIO_WritePin(JOY_CS_GPIO_PORT, JOY_CS_PIN, 0)
#define JOY_CS_HIGH() HAL_GPIO_WritePin(JOY_CS_GPIO_PORT, JOY_CS_PIN, 1)
#define JOY_CS_GPIO_PORT GPIOC
#define JOY_CS_PIN GPIO_PIN_13
int16_t Joy_ReadXY(uint8_t reg1){
uint8_t pTxData1[2] = {reg1, 0};
uint8_t pRxData1[2] = {0, 0};
JOY_CS_LOW();
HAL_SPI_TransmitReceive(&hspi4, pTxData1, pRxData1, 2, HAL_MAX_DELAY);
JOY_CS_HIGH();
return pRxData1[0] << 8 | pRxData1[1];
}
Here, in Main.c, you call the function before telling the compiler about what parameters and what return value types it has.
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4)
That confused the compiler and it starts "guessing" about them.
Guessing that it is a void-returning function, the compiler then complains that you are expecting a return value from a function which does return void i.e. nothing.
The returned void should be ignored, instead of attempting to write it to a variable. At least that is what the compiler thinks...
To fix it, you should explain to the compiler that there is a function elsewhere, with name, parameters and return value type. That is done by providing the prototype
int16_t Joy_ReadXY(uint8_t reg1);
It needs to be done before the function body in which the the extern function is first called. (And you already confirmed in comments that it fixes the described problem in your code.)
Note that for the other shown functions this is not needed, because they are defined (with head and body) before they are called.
Similar for other functions, which have their prototype provided in the header you include early on.
Actually, putting the prototype of your function into a header and including that similarily would be the best way to solve this.
Related
I'm testing the library ESP32TimerInterrupt for ESP32 using the example ISR_16_Timars_Array. While compiling I get errors of missing declarations about the method timer_isr_callback_add and the parameters TIMER_INTR_T0 and TIMER_INTR_T1. Although all the h files included with the library are available to the example, I assume I miss some file inclusion - which one?
And another question - I'm using the board Heltec WiFILoRa 32(V2). To minimize interference with other HW/SW features I prefer using timer 2 - is it possible?
Best regards
Yons Gy
The error messages:
Arduino: 1.8.19 (Windows 10), Board: "WiFi LoRa 32(V2), Disabled, 240MHz (WiFi/BT), 921600, None, REGION_EU868, None"
In file included from D:\Current\Tractor\TractorSW\motion\src\ISR_16_Timers_Array\ISR_16_Timers_Array.ino:23:0:
D:\Current\Tractor\TractorSW\motion\src\ISR_16_Timers_Array\ESP32TimerInterrupt.hpp: In member function 'bool ESP32TimerInterrupt::setFrequency(const float&, bool (* const&)(void*))':
ESP32TimerInterrupt.hpp:329:100: error: 'timer_isr_callback_add' was not declared in this scope
timer_isr_callback_add(_timerGroup, _timerIndex, _callback, (void *) (uint32_t) _timerNo, 0);
^
D:\Current\Tractor\TractorSW\motion\src\ISR_16_Timers_Array\ESP32TimerInterrupt.hpp: In member function 'void ESP32TimerInterrupt::detachInterrupt()':
ESP32TimerInterrupt.hpp:371:66: error: 'TIMER_INTR_T0' was not declared in this scope
timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
^
ESP32TimerInterrupt.hpp:371:82: error: 'TIMER_INTR_T1' was not declared in this scope
timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
^
D:\Current\Tractor\TractorSW\motion\src\ISR_16_Timers_Array\ESP32TimerInterrupt.hpp: In member function 'void ESP32TimerInterrupt::disableTimer()':
ESP32TimerInterrupt.hpp:380:66: error: 'TIMER_INTR_T0' was not declared in this scope
timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
^
ESP32TimerInterrupt.hpp:380:82: error: 'TIMER_INTR_T1' was not declared in this scope
timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
^
D:\Current\Tractor\TractorSW\motion\src\ISR_16_Timers_Array\ESP32TimerInterrupt.hpp: In member function 'void ESP32TimerInterrupt::reattachInterrupt()':
ESP32TimerInterrupt.hpp:390:65: error: 'TIMER_INTR_T0' was not declared in this scope
timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
^
ESP32TimerInterrupt.hpp:390:81: error: 'TIMER_INTR_T1' was not declared in this scope
timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
^
D:\Current\Tractor\TractorSW\motion\src\ISR_16_Timers_Array\ESP32TimerInterrupt.hpp: In member function 'void ESP32TimerInterrupt::enableTimer()':
ESP32TimerInterrupt.hpp:400:65: error: 'TIMER_INTR_T0' was not declared in this scope
timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
^
ESP32TimerInterrupt.hpp:400:81: error: 'TIMER_INTR_T1' was not declared in this scope
timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
^
exit status 1
'timer_isr_callback_add' was not declared in this scope
The code (first - ESP32TimerInterrupt.hpp - library file), then the .ino file:
/****************************************************************************************************************************
ESP32TimerInterrupt.hpp
For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.2+
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/ESP32TimerInterrupt
Licensed under MIT license
The ESP32, ESP32_S2, ESP32_S3, ESP32_C3 have two timer groups, TIMER_GROUP_0 and TIMER_GROUP_1
1) each group of ESP32, ESP32_S2, ESP32_S3 has two general purpose hardware timers, TIMER_0 and TIMER_1
2) each group of ESP32_C3 has ony one general purpose hardware timer, TIMER_0
All the timers are based on 64-bit counters (except 54-bit counter for ESP32_S3 counter) and 16 bit prescalers.
The timer counters can be configured to count up or down and support automatic reload and software reload.
They can also generate alarms when they reach a specific value, defined by the software.
The value of the counter can be read by the software program.
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 ESP32-S2 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.
Based on SimpleTimer - A timer library for Arduino.
Author: mromani#ottotecnica.com
Copyright (c) 2010 OTTOTECNICA Italy
Based on BlynkTimer.h
Author: Volodymyr Shymanskyy
Version: 2.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 23/11/2019 Initial coding
1.0.1 K Hoang 27/11/2019 No v1.0.1. Bump up to 1.0.2 to match ESP8266_ISR_TimerInterupt library
1.0.2 K.Hoang 03/12/2019 Permit up to 16 super-long-time, super-accurate ISR-based timers to avoid being blocked
1.0.3 K.Hoang 17/05/2020 Restructure code. Add examples. Enhance README.
1.1.0 K.Hoang 27/10/2020 Restore cpp code besides Impl.h code to use if Multiple-Definition linker error.
1.1.1 K.Hoang 06/12/2020 Add Version String and Change_Interval example to show how to change TimerInterval
1.2.0 K.Hoang 08/01/2021 Add better debug feature. Optimize code and examples to reduce RAM usage
1.3.0 K.Hoang 06/05/2021 Add support to ESP32-S2
1.4.0 K.Hoang 01/06/2021 Add complex examples. Fix compiler errors due to conflict to some libraries.
1.4.1 K.Hoang 14/11/2021 Avoid using D1 in examples due to issue with core v2.0.0 and v2.0.1
1.5.0 K.Hoang 18/01/2022 Fix `multiple-definitions` linker error
2.0.0 K Hoang 13/02/2022 Add support to new ESP32-S3. Restructure library.
2.0.1 K Hoang 13/03/2022 Add example to demo how to use one-shot ISR-based timers. Optimize code
*****************************************************************************************************************************/
#pragma once
#ifndef ESP32TIMERINTERRUPT_HPP
#define ESP32TIMERINTERRUPT_HPP
#if ( ARDUINO_ESP32S2_DEV || ARDUINO_FEATHERS2 || ARDUINO_ESP32S2_THING_PLUS || ARDUINO_MICROS2 || \
ARDUINO_METRO_ESP32S2 || ARDUINO_MAGTAG29_ESP32S2 || ARDUINO_FUNHOUSE_ESP32S2 || \
ARDUINO_ADAFRUIT_FEATHER_ESP32S2_NOPSRAM )
#define USING_ESP32_S2_TIMERINTERRUPT true
#elif ( defined(ARDUINO_ESP32S3_DEV) || defined(ARDUINO_ESP32_S3_BOX) || defined(ARDUINO_TINYS3) || \
defined(ARDUINO_PROS3) || defined(ARDUINO_FEATHERS3) )
#define USING_ESP32_S3_TIMERINTERRUPT true
#elif ( ARDUINO_ESP32C3_DEV )
#define USING_ESP32_C3_TIMERINTERRUPT true
#elif defined(ESP32)
#define USING_ESP32_TIMERINTERRUPT true
#else
#error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
#endif
#ifndef ESP32_TIMER_INTERRUPT_VERSION
#define ESP32_TIMER_INTERRUPT_VERSION "ESP32TimerInterrupt v2.0.1"
#define ESP32_TIMER_INTERRUPT_VERSION_MAJOR 2
#define ESP32_TIMER_INTERRUPT_VERSION_MINOR 0
#define ESP32_TIMER_INTERRUPT_VERSION_PATCH 1
#define ESP32_TIMER_INTERRUPT_VERSION_INT 2000001
#endif
#ifndef TIMER_INTERRUPT_DEBUG
#define TIMER_INTERRUPT_DEBUG 0
#endif
#if defined(ARDUINO)
#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#endif
#include "TimerInterrupt_Generic_Debug.h"
#include <driver/timer.h>
#include "SimpleTimer.h" // https://github.com/jfturcot/SimpleTimer
/*
//ESP32 core v1.0.6, hw_timer_t defined in esp32/tools/sdk/include/driver/driver/timer.h:
#define TIMER_BASE_CLK (APB_CLK_FREQ) //Frequency of the clock on the input of the timer groups
//#brief Selects a Timer-Group out of 2 available groups
typedef enum
{
TIMER_GROUP_0 = 0, //!<Hw timer group 0
TIMER_GROUP_1 = 1, //!<Hw timer group 1
TIMER_GROUP_MAX,
} timer_group_t;
//#brief Select a hardware timer from timer groups
typedef enum
{
TIMER_0 = 0, //!<Select timer0 of GROUPx
TIMER_1 = 1, //!<Select timer1 of GROUPx
TIMER_MAX,
} timer_idx_t;
//#brief Decides the direction of counter
typedef enum
{
TIMER_COUNT_DOWN = 0, //Descending Count from cnt.high|cnt.low
TIMER_COUNT_UP = 1, //Ascending Count from Zero
TIMER_COUNT_MAX
} timer_count_dir_t;
//#brief Decides whether timer is on or paused
typedef enum
{
TIMER_PAUSE = 0, //Pause timer counter
TIMER_START = 1, //Start timer counter
} timer_start_t;
//#brief Decides whether to enable alarm mode
typedef enum
{
TIMER_ALARM_DIS = 0, //Disable timer alarm
TIMER_ALARM_EN = 1, //Enable timer alarm
TIMER_ALARM_MAX
} timer_alarm_t;
//#brief Select interrupt type if running in alarm mode.
typedef enum
{
TIMER_INTR_LEVEL = 0, //Interrupt mode: level mode
//TIMER_INTR_EDGE = 1, //Interrupt mode: edge mode, Not supported Now
TIMER_INTR_MAX
} timer_intr_mode_t;
//#brief Select if Alarm needs to be loaded by software or automatically reload by hardware.
typedef enum
{
TIMER_AUTORELOAD_DIS = 0, //Disable auto-reload: hardware will not load counter value after an alarm event
TIMER_AUTORELOAD_EN = 1, //Enable auto-reload: hardware will load counter value after an alarm event
TIMER_AUTORELOAD_MAX,
} timer_autoreload_t;
//#brief Data structure with timer's configuration settings
typedef struct
{
bool alarm_en; //Timer alarm enable
bool counter_en; //Counter enable
timer_intr_mode_t intr_type; //Interrupt mode
timer_count_dir_t counter_dir; //Counter direction
bool auto_reload; //Timer auto-reload
uint32_t divider; //Counter clock divider. The divider's range is from from 2 to 65536.
} timer_config_t;
*/
class ESP32TimerInterrupt;
typedef ESP32TimerInterrupt ESP32Timer;
#if USING_ESP32_C3_TIMERINTERRUPT
#define MAX_ESP32_NUM_TIMERS 2
#else
#define MAX_ESP32_NUM_TIMERS 4
#endif
#define TIMER_DIVIDER 80 // Hardware timer clock divider
// TIMER_BASE_CLK = APB_CLK_FREQ = Frequency of the clock on the input of the timer groups
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds
// In esp32/1.0.6/tools/sdk/esp32s2/include/driver/include/driver/timer.h
// typedef bool (*timer_isr_t)(void *);
//esp_err_t timer_isr_callback_add(timer_group_t group_num, timer_idx_t timer_num, timer_isr_t isr_handler, void *arg, int intr_alloc_flags);
//esp_err_t timer_isr_callback_remove(timer_group_t group_num, timer_idx_t timer_num);
//timer_deinit(timer_group_t group_num, timer_idx_t timer_num);
//esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask);
//esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask);
typedef bool (*esp32_timer_callback) (void *);
// For ESP32_C3, TIMER_MAX == 1
// For ESP32 and ESP32_S2, TIMER_MAX == 2
typedef struct
{
timer_idx_t timer_idx;
timer_group_t timer_group;
//int alarm_interval;
//timer_autoreload_t auto_reload;
} timer_info_t;
class ESP32TimerInterrupt
{
private:
timer_config_t stdConfig =
{
.alarm_en = TIMER_ALARM_EN, //enable timer alarm
.counter_en = TIMER_START, //starts counting counter once timer_init called
.intr_type = TIMER_INTR_MAX,
.counter_dir = TIMER_COUNT_UP, //counts from 0 to counter value
.auto_reload = TIMER_AUTORELOAD_EN, // reloads counter automatically
.divider = TIMER_DIVIDER
};
timer_idx_t _timerIndex;
timer_group_t _timerGroup;
uint32_t interruptFlag; // either TIMER_INTR_T0 or TIMER_INTR_T1
uint8_t _timerNo;
esp32_timer_callback _callback; // pointer to the callback function
float _frequency; // Timer frequency
uint64_t _timerCount; // count to activate timer
//xQueueHandle s_timer_queue;
public:
ESP32TimerInterrupt(const uint8_t& timerNo)
{
_callback = NULL;
if (timerNo < MAX_ESP32_NUM_TIMERS)
{
_timerNo = timerNo;
#if USING_ESP32_C3_TIMERINTERRUPT
// Always using TIMER_INTR_T0
_timerIndex = (timer_idx_t) ( (uint32_t) 0 );
// timerNo == 0 => Group 0, timerNo == 1 => Group 1
_timerGroup = (timer_group_t) ( (uint32_t) timerNo);
#else
_timerIndex = (timer_idx_t) (_timerNo % TIMER_MAX);
_timerGroup = (timer_group_t) (_timerNo / TIMER_MAX);
#endif
}
else
{
_timerNo = MAX_ESP32_NUM_TIMERS;
}
};
// frequency (in hertz) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to esp32-hal-timer.c
bool setFrequency(const float& frequency, const esp32_timer_callback& callback)
{
if (_timerNo < MAX_ESP32_NUM_TIMERS)
{
// select timer frequency is 1MHz for better accuracy. We don't use 16-bit prescaler for now.
// Will use later if very low frequency is needed.
_frequency = TIMER_BASE_CLK / TIMER_DIVIDER; //1000000;
_timerCount = (uint64_t) _frequency / frequency;
// count up
#if USING_ESP32_S2_TIMERINTERRUPT
TISR_LOGWARN3(F("ESP32_S2_TimerInterrupt: _timerNo ="), _timerNo, F(", _fre ="), TIMER_BASE_CLK / TIMER_DIVIDER);
TISR_LOGWARN3(F("TIMER_BASE_CLK ="), TIMER_BASE_CLK, F(", TIMER_DIVIDER ="), TIMER_DIVIDER);
TISR_LOGWARN3(F("_timerIndex ="), _timerIndex, F(", _timerGroup ="), _timerGroup);
TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32) , F("-"), (uint32_t) (_timerCount));
TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
#elif USING_ESP32_S3_TIMERINTERRUPT
// ESP32-S3 is embedded with four 54-bit general-purpose timers, which are based on 16-bit prescalers
// and 54-bit auto-reload-capable up/down-timers
TISR_LOGWARN3(F("ESP32_S3_TimerInterrupt: _timerNo ="), _timerNo, F(", _fre ="), TIMER_BASE_CLK / TIMER_DIVIDER);
TISR_LOGWARN3(F("TIMER_BASE_CLK ="), TIMER_BASE_CLK, F(", TIMER_DIVIDER ="), TIMER_DIVIDER);
TISR_LOGWARN3(F("_timerIndex ="), _timerIndex, F(", _timerGroup ="), _timerGroup);
TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32) , F("-"), (uint32_t) (_timerCount));
TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
#else
TISR_LOGWARN3(F("ESP32_TimerInterrupt: _timerNo ="), _timerNo, F(", _fre ="), TIMER_BASE_CLK / TIMER_DIVIDER);
TISR_LOGWARN3(F("TIMER_BASE_CLK ="), TIMER_BASE_CLK, F(", TIMER_DIVIDER ="), TIMER_DIVIDER);
TISR_LOGWARN3(F("_timerIndex ="), _timerIndex, F(", _timerGroup ="), _timerGroup);
TISR_LOGWARN3(F("_count ="), (uint32_t) (_timerCount >> 32) , F("-"), (uint32_t) (_timerCount));
TISR_LOGWARN1(F("timer_set_alarm_value ="), TIMER_SCALE / frequency);
#endif
timer_init(_timerGroup, _timerIndex, &stdConfig);
// Counter value to 0 => counting up to alarm value as .counter_dir == TIMER_COUNT_UP
timer_set_counter_value(_timerGroup, _timerIndex , 0x00000000ULL);
timer_set_alarm_value(_timerGroup, _timerIndex, TIMER_SCALE / frequency);
// enable interrupts for _timerGroup, _timerIndex
timer_enable_intr(_timerGroup, _timerIndex);
_callback = callback;
// Register the ISR handler
// If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, the handler function must be declared with IRAM_ATTR attribute
// and can only call functions in IRAM or ROM. It cannot call other timer APIs.
//timer_isr_register(_timerGroup, _timerIndex, _callback, (void *) (uint32_t) _timerNo, ESP_INTR_FLAG_IRAM, NULL);
timer_isr_callback_add(_timerGroup, _timerIndex, _callback, (void *) (uint32_t) _timerNo, 0);
timer_start(_timerGroup, _timerIndex);
return true;
}
else
{
#if USING_ESP32_C3_TIMERINTERRUPT
TISR_LOGERROR(F("Error. Timer must be 0-1"));
#else
TISR_LOGERROR(F("Error. Timer must be 0-3"));
#endif
return false;
}
}
// interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to esp32-hal-timer.c
bool setInterval(const unsigned long& interval, const esp32_timer_callback& callback)
{
return setFrequency((float) (1000000.0f / interval), callback);
}
bool attachInterrupt(const float& frequency, const esp32_timer_callback& callback)
{
return setFrequency(frequency, callback);
}
// interval (in microseconds) and duration (in milliseconds). Duration = 0 or not specified => run indefinitely
// No params and duration now. To be addes in the future by adding similar functions here or to esp32-hal-timer.c
bool attachInterruptInterval(const unsigned long& interval, const esp32_timer_callback& callback)
{
return setFrequency( (float) ( 1000000.0f / interval), callback);
}
void detachInterrupt()
{
#if USING_ESP32_C3_TIMERINTERRUPT
timer_group_intr_disable(_timerGroup, TIMER_INTR_T0);
#else
timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
#endif
}
void disableTimer()
{
#if USING_ESP32_C3_TIMERINTERRUPT
timer_group_intr_disable(_timerGroup, TIMER_INTR_T0);
#else
timer_group_intr_disable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
#endif
}
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void reattachInterrupt()
{
#if USING_ESP32_C3_TIMERINTERRUPT
timer_group_intr_enable(_timerGroup, TIMER_INTR_T0);
#else
timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
#endif
}
// Duration (in milliseconds). Duration = 0 or not specified => run indefinitely
void enableTimer()
{
#if USING_ESP32_C3_TIMERINTERRUPT
timer_group_intr_enable(_timerGroup, TIMER_INTR_T0);
#else
timer_group_intr_enable(_timerGroup, (_timerIndex == 0) ? TIMER_INTR_T0 : TIMER_INTR_T1);
#endif
}
// Just stop clock source, clear the count
void stopTimer()
{
timer_pause(_timerGroup, _timerIndex);
}
// Just reconnect clock source, start current count from 0
void restartTimer()
{
timer_set_counter_value(_timerGroup, _timerIndex , 0x00000000ULL);
timer_start(_timerGroup, _timerIndex);
}
int8_t getTimer() __attribute__((always_inline))
{
return _timerIndex;
};
int8_t getTimerGroup() __attribute__((always_inline))
{
return _timerGroup;
};
}; // class ESP32TimerInterrupt
#include "ESP32_ISR_Timer.hpp"
#endif // ESP32TIMERINTERRUPT_HPP
INO file:
// These define's must be placed at the beginning before #include "ESP32TimerInterrupt.h"
#define _TIMERINTERRUPT_LOGLEVEL_ 4
#define HW_TIMER_INTERVAL_MS 1L
#define NUMBER_ISR_TIMERS 2
#define LED_TOGGLE_INTERVAL_MS 2000L
#define BLOCKING_TIME_MS 10000L
#define LED 25
long blockingTime;
void doingSomething0(){}
void doingSomething1(){}
uint32_t TimerInterval[NUMBER_ISR_TIMERS] = {1000L, 1500L};
typedef void (*irqCallback)();
irqCallback irqCallbackFunc[NUMBER_ISR_TIMERS] =
{
doingSomething0,
doingSomething1
};
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
#include "ESP32TimerInterrupt.hpp"
//#include "ESP32_ISR_Timer.h"
//#include <SimpleTimer.h> // https://github.com/jfturcot/SimpleTimer
volatile uint32_t startMillis = 0;
ESP32Timer ITimer(1); // Init ESP32 timer 1
ESP32_ISR_Timer ISR_Timer; // Init ESP32_ISR_Timer
/************************************/
bool IRAM_ATTR TimerHandler(void * timerNo)
{
static int timeRun = 0;
ISR_Timer.run();
// Toggle LED every LED_TOGGLE_INTERVAL_MS = 2000ms = 2s
if (++timeRun == (LED_TOGGLE_INTERVAL_MS / HW_TIMER_INTERVAL_MS))
{
timeRun = 0;
//timer interrupt toggles pin LED_BUILTIN
digitalWrite(LED, !digitalRead(LED));
}
return true;
}
/************************************/
void setup()
{
Serial.begin(115200);
while (!Serial);
pinMode(LED, OUTPUT);
delay(200);
Serial.print(F("\nStarting ISR_16_Timers_Array on "));
Serial.println(ARDUINO_BOARD);
Serial.print(ESP32_TIMER_INTERRUPT_VERSION);
Serial.print(F(" runninr at CPU Frequency = "));
Serial.print(F_CPU / 1000000);
Serial.println(F(" MHz"));
// Interval in microsecs
if (ITimer.attachInterruptInterval(HW_TIMER_INTERVAL_MS * 1000, TimerHandler))
{
startMillis = millis();
Serial.print(F("Starting ITimer OK, millis() = "));
Serial.println(startMillis);
}
else
Serial.println(F("Can't set ITimer. Select another freq. or timer"));
// You can use up to 16 timer for each ISR_Timer
for (uint16_t i = 0; i < NUMBER_ISR_TIMERS; i++)
ISR_Timer.setInterval(TimerInterval[i], irqCallbackFunc[i]);
}
/************************************/
void loop()
{
if ((millis() - blockingTime) < BLOCKING_TIME_MS)
return;
blockingTime = millis();
}
I am working on RGB LED project and that's controlled by a PIC12F1572. The software that I am using is MPLAB IDE with the HiTech C compiler. The plan is to use serial communication to send LED RGB combination data commands to the PIC to be stored in a variable that will make it perform the LED blink and glowing I have been able to establish UART communication.Every function or step I code is right by syntax and works on linux command line terminal if I compile..
And it fails if I try to simulate using register injection in MPLAB.I wanted to run it in simulation also (anyone knows how register injection actuallly works in MPLAB?)
The problem I face together when I try to debug . it compiles but doesn't work
here is my code :
Any idea or hint about the problem will be highly appreciated.
I personally fee that placing the code [hierarchical way] may be wrong
Thanks!
#include <xc.h>
#include "mcc.h"
#include "LED.h"
#include "tmr0.h"
#include "interrupt_manager.h"
void SetLedColor(uint16_t R_color, uint16_t G_color, uint16_t B_color);
void main(void)
{
uint8_t data, i, j;
uint16_t R_value, G_value, B_value;
uint8_t value;
uint8_t RX_Buffer[FRAMESIZE] ,RGB_data[6] ,HEX_data[6];
// initialize the device
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptEnable(); // Enable the Global Interrupts
INTERRUPT_PeripheralInterruptEnable(); // Enable the Peripheral Interrupts
while (1)
{
// EUSART_Write(0x61);
while (!RCIF)
{
data = EUSART_Read(); // Read received character
for (i = 0; i < FRAMESIZE; i++)
{
RX_Buffer[i] = data;
}
EUSART_Write(data);
}
//check if any data is received
for (j = 0; j = 5; j++) // get the RGB value in the separate array
{
RGB_data[j] = RX_Buffer[j + 3];
HEX_data[value] = RGB_data[j] / 16;
}
if (RX_Buffer[0] == 'R' && RX_Buffer[FRAMESIZE - 1] == '\n')
{
//ASCII to HEX separate values
// uint32_t number = (uint32_t)strtol(HEX_data, NULL, 16);
// R_value = number >>16;
// G_value = (number & 0xffff) >> 8;
// B_value = (number & 0x0000FF);
R_value = (uint16_t) atoh(HEX_data[0], HEX_data[1]);
G_value = (uint16_t) atoh(HEX_data[2], HEX_data[3]);
B_value = (uint16_t) atoh(HEX_data[4], HEX_data[5]);
}
SetLedColor(R_value, G_value, B_value);
}
}
void SetLedColor(uint16_t R_color, uint16_t G_color, uint16_t B_color)
{
if (R_color == 0xFF)
{
LATAbits.LATA2 = 1;
}
else
{
LATAbits.LATA2 = 0;
}
if (G_color == 0xFF)
{
LATAbits.LATA4 = 1;
}
else
{
LATAbits.LATA4 = 0;
}
if (B_color == 0xFF)
{
LATAbits.LATA5 = 1;
}
else
{
LATAbits.LATA5 = 0;
}
}
So till the receiving the UART frame and echoed back and from the storing data make LED blink , I am able to succeed and this is what I wanted for primary step here by hierarchical way
#include "mcc_generated_files/mcc.h"
#include <stdlib.h>
#include <stdio.h>
#include "atoh.h"
#include "LED.h"
#define _XTAL_FREQ 16000000
#define FRAMESIZE 19
void main(void)
{
uint8_t data,i,j,got_char;
uint8_t R_value, G_value ,B_value;
uint8_t value;
uint8_t RX_Buffer[FRAMESIZE];
uint8_t RGB_data[6] ,HEX_data[6];
// initialize the device
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptEnable(); // Enable the Global Interrupts
INTERRUPT_PeripheralInterruptEnable(); // Enable the Peripheral Interrupts
while (1)
{
if (EUSART_DataReady)
{
for (i = 0; i<FRAMESIZE; i++)
{
RX_Buffer[i] = EUSART_Read();
if (RX_Buffer[i] == '\n')
break;
}
RX_Buffer[i] = '\n'; //append '\n' at the end of stoaring array for detection of frame
RX_Buffer[i+1] = '\0'; // End of an array
EUSART_WriteAnArrayOfBytes(RX_Buffer);
if(RX_Buffer[0]=='R' && RX_Buffer[FRAMESIZE-2] == '\n') //check for correct frame
{
LATAbits.LATA2 = 1;
__delay_ms(2000);
LATAbits.LATA2 = 0;
__delay_ms(1000);
}
}
}
I have faced a problem connected with GPIO interrupt.
The task is to make a simple UI interface, so I need to use 3 buttons.
The problem is that I don't understand how to use GPIO interrupt for different pins and all my buttons work the same way.
here is the code:
#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int value; // the actual value which is used in the module
char string[16]; // string that is printed in LCD for user
} UI_ELEMENT;
#define FIRST_LEVEL 3
#define SECOND_LEVEL 3
#define PWM 0
#define PGA 1
#define ADC 2
#define PWM_STATE 0
#define PWM_PERIOD 1
#define PWM_WIDTH 2
#define PWM_STATE_OFF 0
#define PWM_STATE_ON 1
volatile int buttonRightPressed = 0;
#pragma interrupt_handler buttonRightInt
void buttonRightInt(void){
// disable button interrupt
M8C_DisableIntMask(INT_MSK0, INT_MSK0_GPIO);
buttonRightPressed = 1;
}
void initialize_LCD(void){
LCD_Position(0,0);
LCD_PrCString("PWM");
LCD_Position(1,0);
LCD_PrCString("< select >");
}
void update_LCD(int* lvl1){
if (*lvl1 == PWM || *lvl1 == 3){
LCD_Position(0,0);
LCD_PrCString("PWM");
*lvl1 = 0;
}
else if (*lvl1 == PGA){
LCD_Position(0,0);
LCD_PrCString("PGA");
}
else if (*lvl1 == ADC){
LCD_Position(0,0);
LCD_PrCString("ADC");
}
}
void main(void)
{
UI_ELEMENT userInterface[FIRST_LEVEL][SECOND_LEVEL];
int level_1_steper = PWM;
int i;
M8C_EnableGInt ; // Uncomment this line to enable Global Interrupts
PWM8_EnableInt();
LCD_Start();
M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO);
initialize_LCD(); // set 'PWM' for upper row, '< select >' for lower row
while (1){
if (buttonRightPressed == 1){
for ( i = 0; i < 350; i++);
level_1_steper++;
update_LCD(&level_1_steper);
buttonRightPressed = 0;
// enable button interrupt again
M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO);
}
}
}
Problem resolved! As usually solution is quite simple: use GPIO interrupt but test which button has been pressed. GPIO iterrupt:
void buttonInt(void){ // disable button interrupt
M8C_DisableIntMask(INT_MSK0, INT_MSK0_GPIO);
if (Right_Data_ADDR & Right_MASK) buttonRightPressed = 1;
if (Left_Data_ADDR & Left_MASK) buttonLeftPressed = 1;
if (Select_Data_ADDR & Select_MASK) buttonSelectPressed = 1;
}
Hello I am learning how to use the Uart by using interrupts in Nios and I am not sure how to start. I have made it in polling, but I am not sure how to start using interrupts.
Any help would be appreciated
Here is my code
#include <stdio.h> // for NULL
#include <sys/alt_irq.h> // for irq support function
#include "system.h" // for QSYS defines
#include "nios_std_types.h" // for standard embedded types
#define JTAG_DATA_REG_OFFSET 0
#define JTAG_CNTRL_REG_OFFSET 1
#define JTAG_UART_WSPACE_MASK 0xFFFF0000
#define JTAG_UART_RV_BIT_MASK 0x00008000
#define JTAG_UART_DATA_MASK 0x000000FF
volatile uint32* uartDataRegPtr = (uint32*)JTAG_UART_0_BASE;
volatile uint32* uartCntrlRegPtr = ((uint32*)JTAG_UART_0_BASE +
JTAG_CNTRL_REG_OFFSET);
void uart_SendByte (uint8 byte);
void uart_SendString (uint8 * msg);
//uint32 uart_checkRecvBuffer (uint8 *byte);
uint32 done = FALSE;
void uart_SendString (uint8 * msg)
{
int i = 0;
while(msg[i] != '\0')
{
uart_SendByte(msg[i]);
i++;
}
} /* uart_SendString */
void uart_SendByte (uint8 byte)
{
uint32 WSPACE_Temp = *uartCntrlRegPtr;
while((WSPACE_Temp & JTAG_UART_WSPACE_MASK) == 0 )
{
WSPACE_Temp = *uartCntrlRegPtr;
}
*uartDataRegPtr = byte;
} /* uart_SendByte */
uint32 uart_checkRecvBuffer (uint8 *byte)
{
uint32 return_value;
uint32 DataReg = *uartDataRegPtr;
*byte = (uint8)(DataReg & JTAG_UART_DATA_MASK);
return_value = DataReg & JTAG_UART_RV_BIT_MASK;
return_value = return_value >> 15;
return return_value;
} /* uart_checkRecvBuffer */
void uart_RecvBufferIsr (void* context)
{
} /* uart_RecvBufferIsr */
int main(void)
{
uint8* test_msg = (uint8*)"This is a test message.\n";
//alt_ic_isr_register ( ); // used for 2nd part when interrupts are enabled
uart_SendString (test_msg);
uart_SendString ((uint8*)"Enter a '.' to exist the program\n\n");
while (!done)
{
uint8 character_from_uart;
if (uart_checkRecvBuffer(&character_from_uart))
{
uart_SendByte(character_from_uart);
}
// do nothing
} /* while */
uart_SendString((uint8*)"\n\nDetected '.'.\n");
uart_SendString((uint8*)"Program existing....\n");
return 0;
} /* main */
I am suppose to use the uart_RecvBufferIsr instead of uart_checkRecvBuffer. How can tackle this situation?
You will need to register your interrupt handler by using alt_ic_isr_register(), which will then be called when an interrupt is raised. Details can be found (including some sample code) in this NIOS II PDF document from Altera.
As far as modifying your code to use the interrupt, here is what I would do:
Remove uart_checkRecvBuffer();
Change uart_RecvBufferIsr() to something like (sorry no compiler here so can't check syntax/functioning):
volatile uint32 recv_flag = 0;
volatile uint8 recv_char;
void uart_RecvBufferIsr(void *context)
{
uint32 DataReg = *uartDataRegPtr;
recv_char = (uint8)(DataReg & JTAG_UART_DATA_MASK);
recv_flag = (DataReg & JTAG_UART_RV_BIT_MASK) >> 15;
}
The moral of the story with the code above is that you should keep your interrupts as short as possible and let anything that is not strictly necessary to be done outside (perhaps by simplifying the logic I used with the recv_char and recv_flag).
And then change your loop to something like:
while (!done)
{
if (recv_flag)
{
uart_SendByte(recv_byte);
recv_flag = 0;
}
}
Note that there could be issues with what I've done depending on the speed of your port - if characters are received too quickly for the "while" loop above to process them, you would be losing some characters.
Finally, note that I declared some variables as "volatile" to prevent the compiler from keeping them in registers for example in the while loop.
But hopefully this will get you going.
If I had some enums like
typedef enum {
AN_TRISTATE_0,
AN_TRISTATE_1,
AN_NOTHING,
AN_MOTOR_1,
AN_MOTOR_2,
AN_MOTOR_3,
AN_SENSOR_1,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
and
adc_pin_func_t a_particular_pin = ...
, would it be possible it check if the pin is part of a particular group, e.g pin is part of AN_MOTOR or part of AN_SENSOR, instead of having to check against each item in each possible group.
Or are there more efficient ways of doing this, other than using enums?
Thanks in advance
You could create masks for each of the groups:
typedef enum {
AN_TRISTATE_0 = 0x00001,
AN_TRISTATE_1 = 0x00002,
AN_TRISTATE_MASK = 0x0000f,
AN_NOTHING = 0x00010, // Should this be 0x00000 ?
AN_MOTOR_1 = 0x00100,
AN_MOTOR_2 = 0x00200,
AN_MOTOR_3 = 0x00400,
AN_MOTOR_MASK = 0x00f00,
AN_SENSOR_1 = 0x01000,
AN_SENSOR_2 = 0x02000,
AN_SENSOR_3 = 0x04000,
AN_SENSOR_4 = 0x08000,
AN_SENSOR_5 = 0x10000,
AN_SENSOR_MASK = 0xff000
} adc_pin_func_t;
And then simply test a group against the mask using the & operator:
if (a_particular_pin & AN_SENSOR_MASK)
{
// it's a sensor pin
}
else if (a_particular_pin & AN_MOTOR_MASK)
{
// it's a motor pin
}
EDIT: As others have suggested using a range, then you could probably create a macro for the test, which would allow you to change how the test is performed without the need to change the code (always a good thing):
#define IS_AN_SENSOR(x) (((x) & AN_SENSOR_MASK) != 0)
#define IS_AN_MOTOR(x) (((x) & AN_MOTOR_MASK) != 0)
// etc.
and then the test becomes:
if (IS_AN_SENSOR(a_particular_pin))
{
// it's a sensor pin
}
else if (IS_AN_MOTOR(a_particular_pin))
{
// it's a motor pin
}
// etc
If you then needed to change to using a range then only the macros need to change (and you'd obviously need to define the range min/max):
#define IS_AN_SENSOR(x) ((x) >= AN_SENSOR_START && (x) <= AN_SENSOR_END)
// etc
You are free to choose your enum values, so you could do something like this
typedef enum {
AN_TRISTATE_0 = 0x0001,
AN_TRISTATE_1 = 0x0002,
AN_NOTHING = 0x0000,
AN_MOTOR_1 = 0x0010,
AN_MOTOR_2 = 0x0020,
AN_MOTOR_3 = 0x0030,
AN_SENSOR_1 = 0x0100,
AN_SENSOR_2 = 0x0200,
AN_SENSOR_3, /*and so on*/
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
Then you can compare bits to check categories. For example, a motor type is the only category that will have non-zero (AN_MOTOR_2 & 0x00F0)
You can do a
typedef enum {
AN_TRISTATE_START,
AN_TRISTATE_0 = AN_TRISTATE_START,
AN_TRISTATE_1,
AN_TRISTATE_END = AN_TRISTATE_1,
AN_NOTHING,
AN_MOTOR_START,
AN_MOTOR_1 = AN_MOTOR_START,
AN_MOTOR_2,
AN_MOTOR_3,
AN_MOTOR_END = AN_MOTOR_3,
AN_SENSOR_START,
AN_SENSOR_1 = AN_SENSOR_START,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5,
AN_SENSOR_END = AN_SENSOR_5
} adc_pin_func_t;
bool inline
is_sensor(int pin)
{
return AN_SENSOR_START <= pin
&& pin <= AN_SENSOR_END
}
and then in your code
if ( is_sensor(pin) )
{
/* body */
}
This way you don't have to care about masking particular values. May be useful if groups contain a lot of values.
You can give values to the enum in exponents of 2. Then you can simply use bitwise AND and OR masks. So you can assign values like 1,2,4,8,16,32... so on.
typedef enum {
AN_TRISTATE_0 = 1,
AN_TRISTATE_1 = 2,
AN_NOTHING = 4,
AN_MOTOR_1 = 8,
AN_MOTOR_2 = 16,
AN_MOTOR_3 = 32,
AN_SENSOR_1 = 64,
AN_SENSOR_2 = 128,
AN_SENSOR_3 = 256,
AN_SENSOR_4 = 512,
AN_SENSOR_5 = 1024
} adc_pin_func_t;
Then for checking with motor type, you can AND with (32+16+8) = 56. So pin & 56, if non zero will mean it is of motor type.
If you really like to have some modularity in your enum (the "hard coded" enum values are also a valid method), you can implement a struct with some OOP flavour. The design become more complicated, but the usage is still simple :
#include <stdio.h>
#include <string.h>
// Every enum will have its first value start at the value of the previous enum's last member PLUS ONE
#define OFFSET_ENUM_MOTOR ( sizeof(adc_pin_tristate_t) )
#define OFFSET_ENUM_SENSOR ( OFFSET_ENUM_MOTOR + sizeof(adc_pin_motor_t) )
///////////////////////////////////////////////////////////////////////////////
// Enum
typedef enum {
AN_TRISTATE_0,
AN_TRISTATE_1,
AN_NOTHING
} adc_pin_tristate_t;
typedef enum {
AN_MOTOR_1 = OFFSET_ENUM_MOTOR,
AN_MOTOR_2,
AN_MOTOR_3
} adc_pin_motor_t;
typedef enum {
AN_SENSOR_1 = OFFSET_ENUM_SENSOR,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_sensor_t;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Struct for abstraction
typedef struct adc_pin_func2_t{
// our "enum value"
unsigned int enum_id;
// return is the enum is a motor one
int(*isMotor)(struct adc_pin_func2_t*);
} adc_pin_func2_t;
// Struct
///////////////////////////////////////////////////////////////////////////////
// Member methods : return if the enum is a motor one
int
PinFunc_isMotor(
adc_pin_func2_t *This /* object */
)
{
return ( (This->enum_id>=OFFSET_ENUM_MOTOR) && (This->enum_id<OFFSET_ENUM_SENSOR) );
}
// Creation of the structure
// Initialization
static void
PinFunc_Init(
adc_pin_func2_t *This, /* output */
unsigned int identifier /* old enum identifier */
)
{
// copy members
This->enum_id = identifier;
//copy methods (do not forget to do it !)
This->isMotor = PinFunc_isMotor;
}
// Constructor
adc_pin_func2_t
PinFunc_Create(
unsigned int identifier /* old enum identifier */
)
{
adc_pin_func2_t This;
PinFunc_Init(&This, identifier);
return This;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
main()
{
adc_pin_func2_t pin = PinFunc_Create(AN_NOTHING);
printf("%d \n", pin );
printf("%d \n", pin.isMotor(&pin) );
adc_pin_func2_t pin2 = PinFunc_Create(AN_MOTOR_2);
printf("%d \n", pin2 );
printf("%d \n", pin2.isMotor(&pin2) );
}
The usage of members functions like pin.isMotor(&pin) isn't very elegant (we repeat pin), but it is a shortcoming of C, which is not an OOP language.
If you don't want to have to manually maintain non-overlapping values, then you can very nearly get it all handled for you automatically. The only thing you'll have to figure out is the maximum number of bits in a group:
#define PIN_GROUP_SHIFT 4
#define GET_PIN_GROUP(x) (adc_pin_group_t)((y) >> PIN_GROUP_SHIFT)
#define PIN_GROUP_START(x) XX_GROUP_##x = ((GROUP_##x << PIN_GROUP_SHIFT) - 1),
enum {
GROUP_TRISTATE,
GROUP_NOTHING,
GROUP_MOTOR,
GROUP_SENSOR
} adc_pin_group_t;
typedef enum {
PIN_GROUP_START(TRISTATE)
AN_TRISTATE_0,
AN_TRISTATE_1,
PIN_GROUP_START(NOTHING)
AN_NOTHING,
PIN_GROUP_START(MOTOR)
AN_MOTOR_1,
AN_MOTOR_2,
AN_MOTOR_3,
PIN_GROUP_START(SENSOR)
AN_SENSOR_1,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
To determine the type of an entry in the enum, use GET_PIN_GROUP(x), and compare it to whichever value of the adc_pin_group_t enum. You can even switch on the result, if that's helpful.
However, that AN_NOTHING entry makes me wonder if your enum is meant to line up with specific values for each entry. are specific values associated with the pins, which you may not be able to assign arbitrarily. In that case you might need to try something complicated (which I haven't tested):
#define GET_PIN_VALUE(x) ((x) & ((1 << PIN_GROUP_SHIFT) - 1)
#define PIN_GROUP_START(x) \
WW_GROUP_##x, \
XX_GROUP_##x = (GROUP_##x << PIN_GROUP_SHIFT) \
+ GET_PIN_INDEX(WW_GROUP_##x) - 1,
Where you need to know the value that your original enum would have used, use GET_PIN_INDEX(x).