Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

This content was presented June 6th, 2020

Introduction

Welcome to firmware 104! By now you should have some experience writing simple programs that could run on our controller boards.

...

  1. SPI and I2C communication

  2. The CAN protocol

  3. Code generation

Recap

Here’s a quick rundown of the last lesson:

  • We have multiple hardware libraries that handle interactions with the hardware, including GPIO, PWM, ADCs, and GPIO interrupts.

  • Our schematics are primarily stored on GitHub at https://github.com/uw-midsun/hardware

  • You have to look at the schematic to understand how to talk to an integrated circuit (what pins do what)

  • You need to look at the datasheet of a integrated circuit to understand how to use it (what commands do what)

  • We write driver programs to talk to integrated circuits

SPI and I2C communication

Something we briefly touched on last lesson but didn’t go into detail of is how we actually talk to these integrated circuits. Since these chips can have a huge range of functionality, we need a way to send a variety of commands using a limited number of GPIO pins. 

...

I2C: https://www.circuitbasics.com/basics-of-the-i2c-communication-protocol/

SPI Protocol

SPI communication happens over four wires between a ‘master’ chip (our controller board) and a ‘slave’ chip (the integrated circuit):

...

Here for example, to read the current, we’d send the byte 0x04 (tx_len = 1), and read the 10 bits of return into two bytes (rx_len = 2).

I2C Protocol

I2C is a little more complex, but happens over only two lines:

...

There are multiple clock speed options. Similar to SPI, there are two I2C ports on the STM. You’ll have to check the schematic to determine which one to use. For more info on using I2C commands, check out our ‘smoke_i2c’ project: https://github.com/uw-midsun/firmware_xiv/blob/master/projects/smoke_i2c/src/main.c .

The CAN protocol

So now we know how to talk to chips on the same board as the STM, but what if we want to talk to other boards and other STM chips? To do this, we use CAN, or a Controller Area Network. The CAN protocol is actually really complex, so for this lesson I’ll focus on how we implement it and how we use it.

The bus

CAN messages are transmitted over two wires. Devices on a CAN network are connected in a ‘bus’. Physically, this goes as follows:

...

Since the whole bus is connected, there’s no way to send a message just to one device - any message sent on the bus can be observed by all devices on the bus. To deal with this in software, any reaction to a message has to explicitly state what message it’s reacting to. We’ll come back to this in the code generation section.

Messages

Ignoring how they’re sent for now, CAN messages take one of the two following forms:

...

This is all fine and good, but it could get pretty annoying to pack the right values into the right places every time you want to send a message, especially if you’re mixing data types like having two uint16_ts and one uint32_t. To facilitate this, we use something called code generation.

Code Generation

We actually define all our CAN messages in a separate repo called codegen-tooling-msxiv, found here: https://github.com/uw-midsun/codegen-tooling-msxiv/blob/master/can_messages.asciipb . Have a quick look at this file. In general, we define messages similar to the following:

...

Using code generation makes it much easier and cleaner to work with CAN.

Conclusion

Congrats, you made it through the meat of the firmware tutorials! There’s a couple lessons left, but if you’ve finished this lesson you should be able to take on some small projects. Ask your lead for work!

...

In the next tutorial, we’ll be covering our finite state machine and event queue libraries, as well as how to architect firmware projects and some best practices to follow.

Homework

All three parts should be submitted in the same project, based on previous firmware 10x submission procedures. Put parts 1 and 2 in a separate file from part 3. You don’t need to run parts 1 and 2.

Part 1: I2C

Based on the MSXII pedal board schematics, write a function that writes 0b0010010010100110 to the configuration register, then reads the conversion register.

Hint: you’ll need to look at the schematics for the pedal board and the datasheet for the ADC.

Part 2: SPI

Based on the MSXII charger interface board schematics, write a function that initializes SPI then writes the following information to the CANCTRL register of the CAN controller IC:

...

Then, send the READ STATUS instruction and print the TXB1CNTRL[3] bit from the return.

Part 3: CAN Communication

Write a function that periodically sends a CAN message with id 0xA and a random uint16_t as the body, and requests an ACK with an OK status. Write another function that periodically sends a CAN message with id 0xB and a different random uint16_t as the body.

...