Lab Assignment: Device Interfacing w/ SPI + Data Structures

Objective

 To learn how to create a single dynamic thread-safe driver for Synchronous Serial Port for two separate ports and to communicate with an external SPI Flash device.

This lab will utilize:

  • Mutexes
  • Lookup table structures
  • Function pointers
  • Enumerations
  • Bit field structure mapping
  • Structure mapping

Assignment

Part 1: Design SSP driver

Using the following class template

  1. Implement ALL class methods.
  2. All methods must function work as expected by their comment description.
  3. Note that the transfer function must be protected with a static mutex in the class.
#ifndef LABSPI_H
#define LABSPI_H

class LabSPI
{
private:
    /**
     * Private chip select callback function
     */
    void (*chipSelect)(bool select);
    /**
     * SSP register lookup table structure
     */
    static const LPC_SSP_TypeDef * SSP[] = {LPC_SSP0, LPC_SSP1};
public:
    enum FrameModes
    {
        /* Fill this out based on the datasheet. */
    };

    enum Peripheral
    {
        SSP0 = 0,
        SSP1 = 1
    };

    LabSPI();
    /**
     * 1) Powers on SPPn peripheral
     * 2) Set peripheral clock
     * 2) Sets pins for specified peripheral to MOSI, MISO, and SCK
     * 3) Defines chip select callback function
     * 4) Have a default clock rate, frame format, and bit-transfer
     *
     * @param peripheral which peripheral SSP0 or SSP1 you want to select.
     * @param chipSelect defines a function that will assert the chip select pin based on the select input (ignore active levels, and only use truth).
     * @param enable specifies whether or not you want to automatically enable after init function runs
     * @return true if initialization was successful
     */
    bool init(Peripheral peripheral, void (*chipSelect)(bool select), bool enable);
    /**
     * Set bit transfer size to a specified width.
     * To optimize the code, look for a pattern in the datasheet
     * Try not to use "case" statement or a chain of if-else statements for each possible size.
     *
     * @param data_size_select
     * @return true bit transfer was set successfully
     */
    bool setBitTransfer(uint8_t data_size_select);
    /**
     * Set the frame format for SSP. Although we will only be using SPI,
     * this driver should be capable of the other forms of SSP.
     *
     * @param format is the code format for which synchronous serial protocol you want to use.
     * @return true if frame format bit set written correctly
     */
    bool frameFormat(FrameModes format);
    /**
     * Should set the SSP clock divider register to parameter value.
     *
     * @param divide is the how much to divide the clock for SSP.
     * @return true if clock divider register is set to the divide value.
     */
    bool setClockDivider(uint8_t divide);
    /**
     * Enables the SSPn peripheral
     *
     * @return true if enable bit was set written correctly
     */
    bool enable();
    /**
     * Disables the SSPn peripheral
     *
     * @return true if enable bit was cleared written correctly
     */
    bool disable();
    /**
     * Transfer 1 byte via SSP to an external device using the SSP data register.
     * This region must be protected by a mutex static to this class.
     *
     * @return received byte from external device via SSP data register.
     */
    uint8_t transfer(uint8_t send);

    ~LabSPI();
};

#endif

Code Block 1. SSP Driver Template Class

Part 2: SPI Flash Reader Application

Application is to retrieve the information from the SJOne board's SPI flash's and print the information about each bit (or field of bits) to STDOUT in a nicely formatted human understandable way. If the 7th bit of a status register has been set you cannot simply print that "bit 7 is set". If bit 7 is the busy bit, then print a sentence like, "SPI Flash is currently busy" or "SPI Flash is NOT busy."

We also want to get information about the SPI flash's master record and print that to STDOUT.

WHEN setting the clock in the application, set the clock rate to something reasonable, around 100KHz.
Next lab we will go over clock speeds in more detail.

Requirements

  • Print out the following registers from the SPI FLASH (not the SSP peripheral)
    • Manufacture ID (print 16-bit hex value)
    • 16-bit Device ID (print 16-bit hex value)
    • 16-bit status register
      • Detailed description of each bit's status
      • MUST create and use a bit field structure map for this register.
  • Read page zero (first 512 bytes), and print the following:
    • MUST create and use a structure mapping for the whole 512 byte page.
    • All meaningful contents of the 4 partition table entries.
      • MUST create and use a packed bit field structure for the partition table entries.
    • Boot signature
  • Use a terminal command to execute this application.

What to turn in:

  • Place everything inside of main file or include all relevant files.
  • Turn in the screenshots of terminal output.
  • Logic Analyzer Screenshots
    • Decoded Waveform of SPI retrieving manufacture ID.

For the logic analyzer, you must not forget to include the CS gpio pin otherwise, the waveform will not decode properly.

FAT Information

The first sector (first section of memory) of the flash contains a Master Boot Record (MBR) which has pointers to where the partitions are placed in the storage device.

The first 446 bytes is the bootstrap code area. After that there is a partition table with four entries and then a boot signature (0x55AA). Each entry is 16 bytes long. To see the structure of the Master Boot Record: Sector layout and the structure of the entry can be found here Master Boot Record: Partition table entries.

 Additional Information:

One of the fields in the partition entry is "partition type". This should tell us what type of filesystem is resident on the partition. In our case it should be FAT12 (0x01). The last 8 bytes in the partition entry will tell us the Logical Block Address (LBA) of the first absolute sector in the partition and the total number of sectors in the partition. Essentially, we want to read the sector pointed to by this LBA for the FAT boot sector. That sector will give us the required information (no of clusters, total sectors, etc.. ).

Back to top