LED matrix

This peripheral is an 8x8 LED matrix. It is great for retro-style UI, but obviously it is also very limited.

The names on the pins are slightly different than the ones on the board, so let's look at the connection diagram:

Ground and Vcc are the same as always.

DIN stands for data input, and therefore it is connected to the pin that transmits data from the master to the slave: MOSI (Master Out, Slave In).

SCL stands for shared clock, and CLK stands just for clock. The different naming can be confusing, but both are commonly used, so just be aware of them being the same.

Finally, we have CS (chip select). This is the pin that is used for addressing the peripheral, so, depending on where you connect it, your SPI bus will have one name or another. For example, if you connect CS to CE1 on a Raspberry Pi, then the bus will be SPI0.1, and if you connect CS to CE0, the bus will be SPI0.0.

One thing that stands out with from breakout circuit is that it has output pins on the left-hand side in addition to the input pins on the right. That is to allow chaining; you can connect another matrix to those pins and they will all work together. And not just two; you can chain any number of them (limited by the controller's addressing capability, but quite large anyway). If you want to have rows, you just need to connect the last one from one row to the first one on the next row.

Now that we have the hardware side sorted, let's go into the software. First we need to add a driver to the dependencies on the build.gradle of our module:

dependencies {
[...]
implementation 'com.nilhcem.androidthings:driver-max72xx:+'
}

We mentioned that this is ideal for retro style UI, so we will be doing an animated sprite from Space Invaders. The code looks like this:

private lateinit var ledControl: LedControl
private val timer = Timer()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ledControl = LedControl(SPI_BUS, 1)
initLedMatrix()
timer.schedule(timerTask {
swapSprite()
}, 1000, 1000)
}

override fun onDestroy() {
super.onDestroy()
timer.cancel()
timer.purge()
ledControl.close()
}

Typical initialization is located inside onCreate and cleanup inside onDestroy. The constructor of LedControl is interesting because it has a second parameter, which is the number of chained matrices. For this example, we only use one (8x8).

The rest of the initialization is inside initLedMatrix and then we use a timer to swap the sprite every second.

The initialization of the matrix is as follows:

private fun initLedMatrix() {
for (i in 0 until ledControl.getDeviceCount()) {
ledControl.setIntensity(i, 1)
ledControl.shutdown(i, false)
ledControl.clearDisplay(i)
}
}

This is a generic init method that iterates over all the chained devices (just one in our case) and, for each one of them, sets the intensity to the minimum (intensity varies from 0 to 15), sets shutdown to false -equivalent to enable it-, and clears the display.

Finally, let's take a look at swapSprite:

private var currentSprite = 0

private fun
swapSprite() {
currentSprite++
for (row in 0..7) {
ledControl.setRow(0, row, sprites[currentSprite % sprites.size][row])
}
}

We increment the currentSprite variable and then use the module operator to get the correct one from the array of sprites.

Note that we use the setRow method that receives the device position and a byte that represents the values. The driver also offers an equivalent method to set a column and another one to set an individual pixel.

This driver provides methods to set a row, a column, and a single pixel on the matrix.

The only missing part is the array of sprites, which, in our case, will be just two from the same model of Space Invaders:

val sprites = arrayOf(
byteArrayOf(
0b00011000.toByte(),
0b00111100.toByte(),
0b01111110.toByte(),
0b11011011.toByte(),
0b11111111.toByte(),
0b00100100.toByte(),
0b01011010.toByte(),
0b10100101.toByte()
),
byteArrayOf (
0b00011000.toByte(),
0b00111100.toByte(),
0b01111110.toByte(),
0b11011011.toByte(),
0b11111111.toByte(),
0b01011010.toByte(),
0b10000001.toByte(),
0b01000010.toByte()
)
)

That is just a binary definition of the sprites for positions 0 and 1, but, given that we are using rows, it allows us to visualize the sprite quite well. Feel free to play around, replace them, and add more elements to the array to animate other characters.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.84.32