Skip to content

HAL_GPIO_PIN #3

Description

@MonteShaffer

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...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions