Skip to content

Yet another library to use the 40pin header of the Asus Tinker Board.

License

Notifications You must be signed in to change notification settings

arne48/tinkerboard_io

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Yet another IO library for the Asus Tinker Board

Introduction

Due to some shortcomings with the wiringTB library which Asus provides and my need for direct SPI access without the spidev subsystem I decided to write this minimalistic IO library for the Tinker Board. This is done by the consistent utilization of direct memory access (via virtual memory mapping). The need for direct access was based on the requirements of my project. So I implemented the features I needed plus some nice to have ones for the completeness of feature groups. E.g. including reading from gpios even when I just use them for their output functionality.

Side Note:

In my project I am using a RT Preempt enabled linux kernel (4.4.79) with the Armbian distribution. Due to problems of rt-patching the kernel provided by Asus (tag/1.9 at that time, haven't tried since) I started with a vanilla kernel and backported a lot of changes to re-enable all functionalities I needed (see the following link for additional information). The forked and updated package of armbian can be found here: https://github.com/arne48/armbian_build

This might be helpful for you too. And interfaces that might interfere with the gpio header are disabled.

Features

GPIO

  • Input & Output

The library provides easy to use functions to setup any non-power pin to either an Input or an Output.

  • Pullup & Down settings for Inputs

Functions are provided to set the pulling resistors of pins. The supported types are normal, pullup, pulldown and buskeeper.

  • Drivestrength (mA) for Outputs

For pins operating as an output the max. drive strength can be set to 2, 4, 8 or 12 mA.

SPI

  • SPI0 and SPI2 usable

The image provided by Asus just enables SPI2 which then can be used by spidev via ioctl. This library allows it to utilize both SPI controllers.

  • Up to 66.7MHz clockspeed

The clock-sources of the clock-reset-unit for the SPI controllers are set in a way that they don't depend on the general PLL clock but are using the codec PLL which should be always stable. Further the divider setting allows a maximum clockspeed for the SPI controllers of up to 66.7MHz.

  • Slave Select can be set to any free gpio or none

One functionality which I already missed in wiringPi was to disable the hardware slave select so it can be set by software to a wide variety of pins without sacrificing the still active hardware pin to be disconnected. To allow the most possible flexibility the slave selects were decided to be set by software internally alltogether. By implementing it like this it is possible to use any pin as a slave select which is then automatically operated by the library. Or it is also possible to set no slave select at all and handle it by yourself with as much slaves as needed.

  • SPI modes 0, 1, 2, 3 are supported

The SPI controllers themself support all 4 available SPI modes and so does the library.

  • MSB first and LSB first mode can be set

Via the configuration provided by the library it is possible to set the byte-order if needed.

Examples

The examples are located in the examples directory. They provide a reference to the usage of the library.

  • GPIO Input

In this example all pins are set as inputs with pullups. Once a pin gets toggled by bridging them to GND or releasing them from GND a message will be prompted to the command-line. (End with any key)

  • GPIO Output

In this examples all pins are set to ouput mode and are toggled in an infinite loop. (End with any key)

  • SPI

This example is meant to be a loopback test and sends 64kb via SPI while checking the received data for corruptions.

Brief Documentation

Pin numbering:

The pins are numbered intuitively by their position on the header from 1 (3.3V) to 40 (last gpio). For an overview of the header please check this image from Asus: Link

Error Handling:

To prevent spamming of the console errors are handled quiete and gracefully. If an operation is illegal it will neither crash or print an error message in those cases no operation will be executed and in case of a non-void function a default value will be returned.

Board Init

Maps the hardware into virtual memory and resets header pins to inputs

returns: 1 if initialization was successful otherwise returns 0

int tinkerboard_init(void);

Board De-Init

If gpio memory is available it resets the header and finally will unmap the virtual memory of gpio, cru and spi

void tinkerboard_end(void);

Resetting all pins as Inputs

Resets all pins of header to inputs using pullups

void tinkerboard_reset_header(void);

Get current grf (IOMUX) configuration of pin

Reads the current configuration value of the requested pin from the corresponding grf register. If requested pin is a power-pin it returns 0

pin_number: number of pin to read the grf config of

returns: configuration (IOMUX) of pin. Contact appropriate documentation for further details

uint32_t tinkerboard_get_grf_config(uint32_t pin_number);

Get data direction mode of pin

Reads the data direction register for specified pin and returns its mode as enum. If requested pin is a power-pin it returns Input

pin_number: number of pin to read the data direction config of

returns: data direction of gpio. This can be either Input or Output

enum IOMode tinkerboard_get_gpio_mode(uint32_t pin_number);

Set data direction mode of pin

Sets the data direction of specified pin to Input or Output and also the grf register to gpio

pin_number: number of pin to set the data direction for

mode: direction (Input or Output) to set the pin to

void tinkerboard_set_gpio_mode(uint32_t pin_number, enum IOMode mode);

Set state of pin (if Output)

If gpio is set as an Output this function will set its voltage level to either HIGH or LOW

pin_number: number of output pin to set the voltage level for

state: state to set the pin to (HIGH or LOW)

void tinkerboard_set_gpio_state(uint32_t pin_number, enum IOState state);

Get state of pin (if Input)

If gpio is set as an Input this function will return the current state sensed on Input

pin_number: number of pin to request the current state for

returns: current state that was sensed on Input (HIGH or LOW)

enum IOState tinkerboard_get_gpio_state(uint32_t pin_number);

Setup pullup & down configuration of pin (relevant for Inputs)

This function allows to configure a pulling behaviour for a pin to prevent it from floating eventually. Available configurations are NORMAL_Z, PULLUP, PULLDOWN, BUSKEEPER.

pin_number: number of pin to set the pulling behaviour for

mode: pulling mode to set the specified pin to

void tinkerboard_set_gpio_pud(uint32_t pin_number, enum PUDMode mode);

Set drive strength of pin (relevant for Outputs)

Sets the output drive strength of the specified pin. Available options are DRV2MA, DRV4MA, DRV8MA, DRV12MA.

pin_number: pin to set the output driving strength of

strength: strength to set the specified pin to

void tinkerboard_set_gpio_drive_strength(uint32_t pin_number, enum DriveStrength strength);

Initialize SPI controller

Initializes the requested SPI controller with the configuration passed.

controller: enum of SPI controller to initialize (SPI0 or SPI2)

mode_config: configuration for the SPI controller

void tinkerboard_spi_init(enum SPIController controller, struct spi_mode_config_t mode_config);

De-Initialize SPI controller

Disables specified SPI controller

controller: enum of SPI controller to disable (SPI0 or SPI2)

void tinkerboard_spi_end(enum SPIController controller);

Transfer (send & receive) n-bytes via SPI

Transfers a passed buffer of specified length by using the requested SPI controller and writes received data into receive buffer.

controller: enum of SPI controller to transfer data with (SPI0 or SPI2)

tx_buff: pointer to transfer buffer

rx_buff: pointer to receive buffer

length: length of transfer buffer

mode_config: configuration the SPI controller was initialized with

void tinkerboard_spi_transfer(enum SPIController controller, uint8_t* tx_buff, uint8_t* rx_buff, uint32_t length, struct spi_mode_config_t mode_config);

SPI Configuration struct

This struct contains the configurations to initialize the SPI controller with.

Important: data_frame_size and transfer_mode are exposed for eventual customizations. If their handling is not added the defaults DFS_8 and TRANSMIT_RECEIVE must be used.

clk_divider: defines any even divider >=2 (66.7MHz) to reduce the SPI clock with

clk_mode: defines the SPI clock mode (0, 1, 2 or 3)

data_frame_size: specifies the size of the data frame (DFS_4, DFS_8 or DFS_16)

slave_select: specifies the pin to use as slave select. This can be any free pin. Or if no slave select is needed use define NO_SS.

transfer_mode: transfer mode of SPI controller. (TRANSMIT_RECEIVE, TRANSMIT, RECEIVE). Please read important note.

byte_order: Sets the order the controller transfers bytes by (MSB_FIRST, LSB_FIRST)

struct spi_mode_config_t {
  uint32_t clk_divider;
  uint32_t clk_mode;
  enum SPIDataFrameSize data_frame_size;
  uint32_t slave_select;
  enum SPITransferMode transfer_mode;
  enum SPIByteOrder  byte_order;
};

Installation

For compilation and installation cmake is used. Besides building the library this also supports its installation. By installing the library it is possible to use the provided cmake module to easily make use of the library within your own projects.

CMake make & install

  1. $mkdir build && cd build
  2. $cmake ..
  3. $make
  4. $sudo make install

Usage of find_package() in own project's CMakeLists.txt

  1. Place the cmake module (FindTINKERBOARD_IO.cmake) found in the cmake_module directory somewhere inside of your project.
  2. add set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/PATH_TO_CMAKE_MODULE/") where "PATH_TO_CMAKE_MODULE" is the relative path to the directory containing the module within your project.
  3. now you can use find_package(TINKERBOARD_IO REQUIRED) to get the ${TINKERBOARD_IO_LIBRARIES} and ${TINKERBOARD_IO_INCLUDE_DIRS} variables for further usage.

About

Yet another library to use the 40pin header of the Asus Tinker Board.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published