C/C++ for Microcontrollers - STM32F0 HAL

Warning

This documentation might be outdated.

The STM32F0 Hardware Abstraction Layer (HAL) is used with the C/C++ bindings for microcontrollers to communicate with Bricklets over SPI.

Supported Hardware

This HAL was tested with the following devices:

  • TNG-Bricklet4

But the HAL should work with all projects that use a STM32F0 microcontroller and the stm32cubef0 library from STM.

Note

Some STM32F0 microcontroller only have a small amout of flash and RAM available. See here for some size optimizations.

Testing an Example

This HAL includes an example driver that can be used to run any example provided with the bindings.

Since the HAL is not written for any specific board, you need tho call the bricklet_main() function from your code after you did the initial setup for your board.

The example driver defines four Bricklet ports that are connected to two different SPI hardware units. You need to change the defines at the top of the example driver to fit to your board layout.

Note

The HAL uses the bricklib2 to implement the timer, sleep and log functions. If you make your own board you will likely have to replace these implementations with timer, sleep and log functions that are available in your project.

Additionally the STM32F0 HAL uses a coop task (non-preemptive scheduling). You can either replace it with similar functions if available or disable the scheduling support with a define at the top of the file hal_stm32f0.c.

By default the HAL uses IRQs 2, 3, 4 and 5 for SPI communication. If you need any of these IRQs for other hardware units in your project, you will also have to change/remove the DMA-IRQ-Handler implementation.

Port Specification Format

A port is specified as an instance of the TF_Port structure:

struct TF_Port {
  TF_STMGPIO clk;
  TF_STMGPIO mosi;
  TF_STMGPIO miso;
  TF_STMGPIO *cs;
  uint8_t cs_count;

  SPI_TypeDef *spi_instance;

  IRQn_Type irq_tx;
  IRQn_Type irq_rx;

  DMA_Channel_TypeDef *dma_channel_rx;
  DMA_Channel_TypeDef *dma_channel_tx;
}

typedef struct {
  GPIO_InitTypeDef pin;
  GPIO_TypeDef *port;
} TF_STMGPIO

The TF_Port struct for the STM32F0 HAL uses the typical stm32cubef0 GPIO, SPI and DMA data types. For details take a look at the example_driver.c.

It contains an example port specification.

API

Most functions of the HAL return an error code (e_code).

Possible error codes are (as defined in errors.h):

  • TF_E_OK = 0
  • TF_E_TIMEOUT = -1
  • TF_E_INVALID_PARAMETER = -2
  • TF_E_NOT_SUPPORTED = -3
  • TF_E_UNKNOWN_ERROR_CODE = -4
  • TF_E_STREAM_OUT_OF_SYNC = -5
  • TF_E_INVALID_CHAR_IN_UID = -6
  • TF_E_UID_TOO_LONG = -7
  • TF_E_UID_OVERFLOW = -8
  • TF_E_TOO_MANY_DEVICES = -9
  • TF_E_DEVICE_NOT_FOUND = -10
  • TF_E_WRONG_DEVICE_TYPE = -11
  • TF_E_LOCKED = -12
  • TF_E_PORT_NOT_FOUND = -13
  • TF_E_NULL = -14
  • TF_E_DEVICE_ALREADY_IN_USE = -15
  • TF_E_WRONG_RESPONSE_LENGTH = -16
  • TF_E_NOT_INITIALIZED = -17

The HAL defines the following further error codes:

  • TF_E_CHIP_SELECT_FAILED = -100
  • TF_E_TRANSCEIVE_FAILED = -101
  • TF_E_TRANSCEIVE_TIMEOUT = -102

Use tf_hal_strerror() to get an error string for an error code.

Basic Functions

int tf_hal_create(TF_HAL *hal, TF_Port *ports, uint8_t spi_port_count)

Creates a HAL object that can be used to list the available devices. It is also required for the constructor of Bricks and Bricklets.

  • ports is an array of port specifications, as described here
  • port_count is the length of the ports array.
int tf_hal_destroy(TF_HAL *hal)

Destroys the given TF_HAL.

void tf_hal_set_timeout(TF_HAL *hal, uint32_t timeout_us)

Sets the timeout in microseconds for getters and for setters for which the response expected flag is activated.

The default timeout is 2500000 (2.5 seconds).

uint32_t tf_hal_get_timeout(TF_HAL *hal)

Returns the timeout as set by tf_hal_set_timeout().

int tf_hal_get_device_info(TF_HAL *hal, uint16_t index, char ret_uid[7], char *ret_port_name, uint16_t *ret_device_id)

Returns the UID, port and device identifier of the nth (=index) detected device. This function returns TF_E_DEVICE_NOT_FOUND if the index was equal or higher than the number of detected devices. To list all devices you can call this function in a loop with growing index until TF_E_DEVICE_NOT_FOUND is returned once.

int tf_hal_callback_tick(TF_HAL *hal, uint32_t timeout_us)

Polls for callbacks on all devices with an registered callback handler. Will block for the given timeout in microseconds.

This function can be used in a non-blocking fashion by calling it with a timeout of 0. The bindings will then poll a single device for one callback, by clocking out a single byte over SPI, returning immediately if no callback is available. If the device starts sending a callback packet, it will be received, acked and the callback handler will be called.

The polling is scheduled round-robin over multiple calls, so even if you only poll with a timeout of 0, all devices will be polled as fairly as possble.

bool tf_hal_deadline_elapsed(TF_HAL *hal, uint32_t deadline_us)

Returns true if the deadline in microseconds is elapsed, false otherwise. Robust against overflows up to UINT32_MAX / 2.

int tf_hal_get_error_counters(TF_HAL *hal, char port_name, uint32_t *ret_spitfp_error_count_checksum, uint32_t *ret_spitfp_error_count_frame, uint32_t *ret_tfp_error_count_frame, uint32_t *ret_tfp_error_count_unexpected)

Returns the error counters for the given port. The following errors are counted:

  • spitfp_error_count_checksum: Received SPITFP packets that where ignored because of a wrong checksum
  • spitfp_error_count_frame: Received SPITFP packets with an invalid length
  • tfp_error_count_frame: Received TFP packets with an invalid length
  • tfp_error_count_unexpected: Received TFP packets that where unexpected because they responded to unknown requests
void tf_hal_log_error(const char *format, ...)

Logs an error if the log level in bindings/config.h is TF_LOG_LEVEL_ERROR or more. Supports a subset of the standard printf syntax. See tf_hal_printf() for details.

void tf_hal_log_info(const char *format, ...)

Logs an information if the log level in bindings/config.h is TF_LOG_LEVEL_INFO or more. Supports a subset of the standard printf syntax. See tf_hal_printf() for details.

void tf_hal_log_debug(const char *format, ...)

Logs a debug message if the log level in bindings/config.h is TF_LOG_LEVEL_DEBUG or more. Supports a subset of the standard printf syntax. See tf_hal_printf() for details.

void tf_hal_printf(const char *format, ...)

This function is a minimalistic printf implementation. The following placeholders are supported:

  • %[prefix]u: An unsigned integer value printed in base 10
  • %[prefix]d: A signed integer value printed in base 10
  • %[prefix]b: An unsigned integer value printed in base 2
  • %[prefix]x and %[prefix]X: An unsigned integer value printed in base 16, in both cases with lower-case letters
  • %c: A single character
  • %s: A zero terminated string
  • %%: A percent sign

With the prefix, you can control the width of printed integers. Valid prefixes are I8, I16, I32 and I64. For example using the placeholder %I16x will print a 16 bit integer hexadecimal.

No padding, grouping , l-modifiers or similar, or floats are supported. The newline character \n is translated to the platform specific newline character(s).

const char *tf_hal_strerror(int e_code)

Returns an error string for the given error code.