Hi Alex,
I wanted to provide an update of HAL_GPIO_PIN based on the initial code base you provided. Specifically I wanted to "bind" the functions to a global structure...
#include <stdint.h>
#include <stdbool.h>
#ifndef _HAL_GPIO_H_
#define _HAL_GPIO_H_
/*- Definitions -------------------------------------------------------------*/
#define HAL_GPIO_PORTA 0
#define HAL_GPIO_PORTB 1
#define HAL_GPIO_PORTC 2
#define HAL_GPIO_PMUX_A 0
#define HAL_GPIO_PMUX_B 1 /* see Table 7-1 of datasheet:: all ADCs are on PMUX_B for SAMD21 */
#define HAL_GPIO_PMUX_C 2
#define HAL_GPIO_PMUX_D 3
#define HAL_GPIO_PMUX_E 4
#define HAL_GPIO_PMUX_F 5
#define HAL_GPIO_PMUX_G 6
#define HAL_GPIO_PMUX_H 7
#define HAL_GPIO_PMUX_I 8
typedef struct ADC_pin {
char * pin_name;
char pin_port;
uint8_t pin_num;
uint8_t pin_ref;
uint8_t pmux;
void (*set)(void);
void (*clr)(void);
void (*toggle)(void);
void (*write)(int);
void (*input)(void);
void (*output)(void);
void (*pullen)(int);
int (*read)(void);
int (*state)(void);
void (*pmuxen)(int);
void (*pmuxdis)(void);
uint8_t has_init;
} ADC_pin;
/* _ref_ is in Table 7-1, represents AIN[bracket PIN number] */
#define SURROUND_H(q,c) q##c##q
#define QUOTE '
#define SURROUND(q,c) SURROUND_H(q,c)
#define CHARIFY(c) SURROUND(QUOTE, c)
//#define HAL_GPIO_ADC(name, port, pin, ...)
#define HAL_GPIO_PIN(name, port, pin, pmux_val, _ref_) \
static inline void HAL_GPIO_##name##_set(void) \
{ \
PORT->Group[HAL_GPIO_PORT##port].OUTSET.reg = (1 << pin); \
(void)HAL_GPIO_##name##_set; \
} \
\
static inline void HAL_GPIO_##name##_clr(void) \
{ \
PORT->Group[HAL_GPIO_PORT##port].OUTCLR.reg = (1 << pin); \
(void)HAL_GPIO_##name##_clr; \
} \
\
static inline void HAL_GPIO_##name##_toggle(void) \
{ \
PORT->Group[HAL_GPIO_PORT##port].OUTTGL.reg = (1 << pin); \
(void)HAL_GPIO_##name##_toggle; \
} \
\
static inline void HAL_GPIO_##name##_write(int value) \
{ \
if (value) \
PORT->Group[HAL_GPIO_PORT##port].OUTSET.reg = (1 << pin); \
else \
PORT->Group[HAL_GPIO_PORT##port].OUTCLR.reg = (1 << pin); \
(void)HAL_GPIO_##name##_write; \
} \
\
static inline void HAL_GPIO_##name##_input(void) \
{ \
PORT->Group[HAL_GPIO_PORT##port].DIRCLR.reg = (1 << pin); \
PORT->Group[HAL_GPIO_PORT##port].PINCFG[pin].reg |= PORT_PINCFG_INEN; \
(void)HAL_GPIO_##name##_input; \
} \
\
static inline void HAL_GPIO_##name##_output(void) \
{ \
PORT->Group[HAL_GPIO_PORT##port].DIRSET.reg = (1 << pin); \
PORT->Group[HAL_GPIO_PORT##port].PINCFG[pin].reg |= PORT_PINCFG_INEN; \
(void)HAL_GPIO_##name##_output; \
} \
\
static inline void HAL_GPIO_##name##_pullen(int state) \
{ \
if (state) \
PORT->Group[HAL_GPIO_PORT##port].PINCFG[pin].reg |= PORT_PINCFG_PULLEN; \
else \
PORT->Group[HAL_GPIO_PORT##port].PINCFG[pin].reg &= ~PORT_PINCFG_PULLEN; \
(void)HAL_GPIO_##name##_pullen; \
} \
\
static inline int HAL_GPIO_##name##_read(void) \
{ \
return (PORT->Group[HAL_GPIO_PORT##port].IN.reg & (1 << pin)) != 0; \
(void)HAL_GPIO_##name##_read; \
} \
\
static inline int HAL_GPIO_##name##_state(void) \
{ \
return (PORT->Group[HAL_GPIO_PORT##port].DIR.reg & (1 << pin)) != 0; \
(void)HAL_GPIO_##name##_state; \
} \
\
static inline void HAL_GPIO_##name##_pmuxen(int mux) \
{ \
PORT->Group[HAL_GPIO_PORT##port].PINCFG[pin].reg |= PORT_PINCFG_PMUXEN; \
if (pin & 1) \
PORT->Group[HAL_GPIO_PORT##port].PMUX[pin>>1].bit.PMUXO = mux; \
else \
PORT->Group[HAL_GPIO_PORT##port].PMUX[pin>>1].bit.PMUXE = mux; \
(void)HAL_GPIO_##name##_pmuxen; \
} \
\
static inline void HAL_GPIO_##name##_pmuxdis(void) \
{ \
PORT->Group[HAL_GPIO_PORT##port].PINCFG[pin].reg &= ~PORT_PINCFG_PMUXEN; \
(void)HAL_GPIO_##name##_pmuxdis; \
} \
\
ADC_pin g_##name = { \
.pin_name = #name, \
.pin_port = CHARIFY(port), \
.pin_num = pin, \
.pin_ref = _ref_, \
.pmux = pmux_val, \
.set = &HAL_GPIO_##name##_set, \
.clr = &HAL_GPIO_##name##_clr, \
.toggle = &HAL_GPIO_##name##_toggle, \
.write = &HAL_GPIO_##name##_write, \
.input = &HAL_GPIO_##name##_input, \
.output = &HAL_GPIO_##name##_output, \
.pullen = &HAL_GPIO_##name##_pullen, \
.read = &HAL_GPIO_##name##_read, \
.state = &HAL_GPIO_##name##_state, \
.pmuxen = &HAL_GPIO_##name##_pmuxen, \
.pmuxdis = &HAL_GPIO_##name##_pmuxdis, \
.has_init = 0 }
#endif
Thereafter, adc.h has some updated functions ...
#include <stdint.h>
#include "hal_gpio.h"
#ifndef _ADC_H_
#define _ADC_H_
/*- Prototypes --------------------------------------------------------------*/
void adc_deinit(ADC_pin * myPIN);
void adc_init(ADC_pin * myPIN);
void adc_update(ADC_pin * myPIN);
int adc_read(void);
int getVoltageFromADC(ADC_pin * myPIN);
#endif // _ADC_H_
which are detailed in adc.c
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "samd21.h"
#include "hal_gpio.h"
#include "nvmdata.h"
#include "adc.h"
void adc_deinit(ADC_pin * myPIN) {
myPIN->has_init = 0;
}
void adc_init(ADC_pin * myPIN) {
if(!myPIN->has_init) {
myPIN->input();
myPIN->pmuxen(myPIN->pmux);
myPIN->has_init = 1;
}
}
void adc_update(ADC_pin * myPIN) {
//adc_init();
PM->APBCMASK.reg |= PM_APBCMASK_ADC;
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(ADC_GCLK_ID) |
GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);
ADC->CTRLA.reg = ADC_CTRLA_SWRST;
while (ADC->CTRLA.reg & ADC_CTRLA_SWRST);
ADC->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1 | ADC_REFCTRL_REFCOMP;
ADC->CTRLB.reg = ADC_CTRLB_RESSEL_16BIT | ADC_CTRLB_PRESCALER_DIV32;
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_128;
ADC->INPUTCTRL.reg = myPIN->pin_ref | ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_GAIN_DIV2;
//ADC->INPUTCTRL.reg = HAL_GPIO_PINA3_getMyVal() | ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_GAIN_DIV2;
ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(NVM_READ_CAL(ADC_BIASCAL)) |
ADC_CALIB_LINEARITY_CAL(NVM_READ_CAL(ADC_LINEARITY));
ADC->CTRLA.reg = ADC_CTRLA_ENABLE;
}
int adc_read(void)
{
ADC->SWTRIG.reg = ADC_SWTRIG_START;
while (0 == (ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY));
int result = ADC->RESULT.reg;
return result;
}
Altogether, I now have my function I wanted ...
int getVoltageFromADC(ADC_pin * myPIN);
int getVoltageFromADC(ADC_pin * myPIN) {
adc_init(myPIN);
adc_update(myPIN);
return adc_read();
}
Which is initiated as follows:
HAL_GPIO_PIN(PINA3, A, 3, HAL_GPIO_PMUX_B, ADC_INPUTCTRL_MUXPOS_PIN1);
// above passes more parameters and makes a global structure with pointers to the functions defined therein. The structure name is g_PINA3. The functions are bound to this struct
int cvolt = getVoltageFromADC(g_PINA3);
I like the HAL_GPIO_PIN, and now realize you use it for all pins, LED/DAC, not juse ADC... we may want to update our structure to "replace ADC_PIN with GPIO_PIN" in the struct
I changed _in() and _out() to _input() and _output()
... we tried to make the macro variadic, but didn't seem worth the trouble, so we passes MUX, PIN_REF as extra parameters...
Comments are welcome...