Porting to New Hardware

Name

Porting -- Adding SPI support to new hardware

Description

Adding SPI support to an eCos port can take two forms. If there is already an SPI bus driver for the target hardware then both that driver and this generic SPI package CYGPKG_IO_SPI should be included in the ecos.db target entry. Typically the platform HAL will need to supply some platform-specific information needed by the bus driver. In addition the platform HAL should provide cyg_spi_device structures for every device attached to the bus. The exact details of this depend on the bus driver so its documentation should be consulted for further details. If there is no suitable SPI bus driver yet then a new driver package will have to be written.

Adding a Device

The generic SPI package CYGPKG_IO_SPI defines a data structure cyg_spi_device. This contains the information needed by the generic package, but not the additional information needed by a bus driver to interact with the device. Each bus driver will define a larger data structure, for example cyg_mcf52xx_qspi_device, which contains a cyg_spi_device as its first field. This is analogous to C++ base and derived classes, but without any use of virtual functions. The bus driver package should be consulted for the details.

During initialization an SPI bus driver may need to know about all the devices attached to that bus. For example it may need to know which cpu pins should be configured as chip selects rather than GPIO pins. To achieve this all device definitions should specify the particular bus to which they are attached, for example:

struct cyg_mcf52xx_qspi_device hal_spi_atod CYG_SPI_DEVICE_ON_BUS(0) =
{
    .spi_common.spi_bus = &cyg_mcf52xx_qspi_bus,
    …
};
    

The CYG_SPI_DEVICE_ON_BUS macro adds information to the structure which causes the linker to group all such structures in a single table. The bus driver's initialization code can then iterate over this table.

Adding Bus Support

An SPI bus driver usually involves a new hardware package. This needs to perform the following:

  1. Define a device structure which contains a cyg_spi_device as its first element. This should contain all the information needed by the bus driver to interact with a device on that bus.

  2. Provide functions for the following operations:

    spi_transaction_begin
    spi_transaction_transfer
    spi_transaction_tick
    spi_transaction_end
    spi_get_config
    spi_set_config

    These correspond to the main API functions, but can assume that the bus is already locked so no other thread will be manipulating the bus or any of the attached devices. Some of these operations may be no-ops.

  3. Define a bus structure which contains a cyg_spi_bus as its first element. This should contain any additional information needed by the bus driver.

  4. Optionally, instantiate the bus structure. The instance should have a well-known name since it needs to be referenced by the device structure initializers. For some drivers it may be best to create the bus inside the driver package. For other drivers it may be better to leave this to the platform HAL or the application. It depends on how much platform-specific knowledge is needed to fill in the bus structure.

  5. Create a HAL table for the devices attached to this bus.

  6. Arrange for the bus to be initialized early on during system initialization. Typically this will happen via a prioritized static constructor with priority CYG_INIT_BUS_SPI. As part of this initialization the bus driver should invoke the CYG_SPI_BUS_COMMON_INIT macro on its cyg_spi_bus field.

  7. Provide the appropriate documentation, including details of how the SPI device structures should be initialized.

There are no standard SPI testcases. It is not possible to write SPI code without knowing about the devices attached to the bus, and those are inherently hardware-specific.