GithubHelp home page GithubHelp logo

dgw's Introduction

USB HID Data Gateway

At the moment, this project is a simple USB stack implementation for Atmel SAM D21 (D11).

Demo application is a very simple and inefficient USB HID to I2C, SPI, GPIO, ADC, DAC and PWM adapter.

Demo CLI application uses I/O1 Xplained Pro board to:

  • Read/write EEPROM and read temperature from the AT30TSE785
  • Test if GPIO1 and GPIO2 pins are shorted to demo GPIO capabilities
  • Test SD Card interface (SPI mode)
  • Test ADC (PA03) and DAC (PA02).
  • Test PWM (PA10 and PA11)

I/O1 Xplained Pro has to be attached to EXT1 connector of the SAM D21 Xplained Pro board.

Future versions will improve on this and implement other interfaces.

dgw's People

Contributors

ataradov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

dgw's Issues

i2c_write_byte infinite loop

I'm using the function i2c_write_byte but it may happen that it never exits the while(1) loop:

//-----------------------------------------------------------------------------
bool i2c_write_byte(uint8_t byte)
{
  I2C_SERCOM->I2CM.DATA.reg = byte;

  while (1)
  {
    int flags = I2C_SERCOM->I2CM.INTFLAG.reg;

    if (flags & SERCOM_I2CM_INTFLAG_MB)
      break;

    if (flags & (SERCOM_I2CM_INTFLAG_SB | SERCOM_I2CM_INTFLAG_ERROR))
      return false;
  }

  if (I2C_SERCOM->I2CM.STATUS.reg & SERCOM_I2CM_STATUS_RXNACK)
  {
    I2C_SERCOM->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
    return false;
  }

  return true;
}

That's because neither of the two conditions are met. What scenario does each condition represent?
This is my test code, i reckon I'm doing the initialization correctly:


  i2c_init(100000); //100KHz
  i2c_start(0x20);
  if(!i2c_write_byte(255)) //0xFF == 11111111
  {
    //not okay
  }
  i2c_stop();

Question for usb_handle_standard_request...

Hello Alex,
I have one question:
If the usb hid report descriptor has a size of 64 bytes or a multiple of 64 bytes, we shouldn't check this and send a zero-length packet at end?

uint16_t length = request->wLength;

Maybe like this:

case USB_CMD(IN, INTERFACE, STANDARD, GET_DESCRIPTOR):
{
     uint16_t length = request->wLength;
     uint16_t total_len= sizeof(usb_hid_report_descriptor);
     bool need_zlp = !(length & (usb_device_descriptor.bMaxPacketSize0 - 1));

    if (length <= total_len)
        need_zlp = false;
    else 
        length = total_len;

    udc_control_send((uint8_t *)usb_hid_report_descriptor, length);

    if (need_zlp)
	udc_control_send_zlp();	
} break;

Potential issue in embedded/spi_master.c

Thanks for this great source of info. I've been reading your code to learn about programming the SAMD21.

I found a potential issue in the SPI code: when calling spi_ss(1) at the end of a transmission, you need to make sure that the transmit buffer is empty before unselecting the slave to avoid losing the last character with some slaves.

I would rewrite spi_ss as follows:

void spi_ss(int state)
{
  if (state)
  {
     while (SPI_SERCOM.INTFLAG.bit.TXC==0);        // Wait for transmit to finish
     SPI_SERCOM->SPI.INTFLAG.bit.TXC = 1;          // clear Int flag
     HAL_GPIO_SS_write(1);
  }
  else
  {
     HAL_GPIO_SS_write(0);
  }
}

In my case, I broke down this call in two functions: spi_begin() and spi_end(), following the same idea.

HAL_GPIO_PIN

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

F_CPU is not defined

Hi,

embedded/debug.c refers to setting up debugger for UART,

line 47 refers to F_CPU which doesn't seem to be defined for the SAMD21.

спасибо

monte

{x:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.