This is a discussion on how we identify devices (peripherals or internal MCU 
devices) through the HAL (Hardware abstraction layer).

A picture is posted to jira here.

https://issues.apache.org/jira/secure/attachment/12795673/hal_drawing.pdf

Here is the gist of the design.

A BSP defines a set of SYSID (System IDS).  This is an enumeration of all the 
devices that the system has.  Remembers, the system includes the built in MCU 
peripherals and also the external peripherals.  The BSP puts these system ids 
into /hw/bsp/include/bsp/bsp_sysid.h

An Example for Arduino might be:

Enum SystemDeviceDescriptor {
     ARDUINO_ANALOG0,   ARDUINO_ANALOG1,     ARDUINO_ANALOG2,     
ARDUINO_ANALOG3,     ARDUINO_ANALOG4,     ARDUINO_ANALOG5,
     ARDUINO_DIGITAL0,     ARDUINO_DIGITAL1,     ARDUINO_DIGITAL2,     
ARDUINO_DIGITAL3,     ARDUINO_DIGITAL4,     ARDUINO_DIGITAL5,
     ARDUINO_DIGITAL6,     ARDUINO_DIGITAL7,     ARDUINO_DIGITAL8,     
ARDUINO_DIGITAL9,     ARDUINO_DIGITAL10,     ARDUINO_DIGITAL11,
     ARDUINO_DIGITAL12,     ARDUINO_DIGITAL13,
     ARDUINO_UART,
     ARDUINO_SPI,
     ARDUINO_PWM8,     ARDUINO_PWM9,     ARDUINO_PWM10,     ARDUINO_PWM11,     
ARDUINO_PWM12,     ARDUINO_PWM13,
}

An example for a fictitious weather monitor which has two analog temp sensors, 
flash storage, a SPI bus with two peripherals, a clock and a display each 
activate with a different digital chip select.  NOTE: Its likely this would 
have more digital lines for power saving, battery control etc.

Enum SystemDeviceDescriptor {
WEATHERMON_ANALOG_TEMP_INDOOR,
WEATHERMON_ANALOG_TEMP_OUTDOOR,
WEATHERMON_FLASH,
WEATHERMON_SPI,
WEATHERMON_DIG_CLOCK_CS,
WEATHERMON_DIG_DISPLAY_CS,
...
};

A few NOTES.   This is not necessarily a mapping of PINS.  For example, the 
UART uses D0 and D1.  PWM8 Uses D8 etc. SO there will be conflicts if apps try 
to use certain combinations.  We haven't designed a pinmux API, but I think 
that will live underneath this.   In general though, the BSP designer will be 
making the tradeoffs about which devices are used in the system.  Since this 
largely depends on how the pins of the MCU are assigned, there won't be too 
many overlaps with this list, but in general, there will be some.

It was a design decision to include all the system devices within a single 
SYSID space (just one enum).  An alternative could have had a separate enum for 
each HAL.  This decision was made for two reasons. One, to keep all the BSP 
devices easily accessible in the same place. This means that APP designers 
don't need to learn or know that much to use the devices.  The tradeoff here is 
that is may not be as obvious which device is which HAL.   The convention to 
make device identification easier is to use descriptive names like above.  Two, 
to make it clear that in a BSP (as opposed to MCU), the BSP designer is making 
tradeoffs to support only some functionality depending on the schematic.  
Generally, the MCUs have tons of pinmux flexibility with more internal devices 
than there are accessible pins.

The SYSID is used in only one place in the HAL.  Each HAL interface has a 
hal_xxx_init function which takes the SYSID of the device and returns a device 
object to the application.  The benefit of this is that the application does 
not need to statically pick a specific MCU object. This allows the application 
or library flexibility to work across multiple different platforms (which is 
the main goal of a HAL).

The rest of the HAL interface is invisible to the application or library.  
Below is a description of how its recommended to work for the MCU or peripheral 
designer but is a convention only.

The MCU or peripheral implementation implements the hal_xxx_int.h driver API 
plus one extra function.   By convention the prototype for this function is 
stored in mcu/hal_xxx.h or periph/hal_xxx.h

The header file includes a single function to create a device of this type and 
the configuration structure to go with it.  Typically, this function will take 
some configuration options which are typically a constant structure (so it 
doesn't use any RAM space).  For example, for an ADC device it might look like 
this.  This configuration structure is where pin mappings or choices would go 
(if there are any).


/* this structure is passed to the BSP for configuration options */
enum samd_adc_reference_voltage {
DEVICE_ID_ADC_REFERENCE_INT1V,
DEVICE_ID_ADC_REFERENCE_INTVCC0,
DEVICE_ID_ADC_REFERENCE_INTVCC1,
DEVICE_ID_ADC_REFERENCE_AREFA ,
DEVICE_ID_ADC_REFERENCE_AREFB,
};

/* this device supports 6 channels */
enum samd_adc_analog_channel {
    ANALOG_CHANNEL_0 = 0,    ANALOG_CHANNEL_1,    ANALOG_CHANNEL_2,    
ANALOG_CHANNEL_3,    ANALOG_CHANNEL_4,    ANALOG_CHANNEL_5,    ANALOG_CHANNEL_5,
    ANALOG_CHANNEL_6, ... , ANALOG_CHANNEL_18, ANALOG_CHANNEL_19, 
ANALOG_CHANNEL_20, ANALOG_CHANNEL_TEMP, ANALOG_CHANNEL_DAC,
};

struct samd21_adc_config {
    enum samd_adc_analog_channel    analog_channels;
    enum samd_adc_reference_voltage volt;
    int                             voltage_mvolts;
};

/* This creates a new ADC object for this ADC source */
struct hal_adc_device_s *
samd21_adc_create(const struct samd21_adc_config *pconfig);













Reply via email to