Skip to content

Commit

Permalink
max72xx: add support for up to 8 devices in series
Browse files Browse the repository at this point in the history
  • Loading branch information
irai committed Dec 21, 2024
1 parent 0623bb4 commit efc1302
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 13 deletions.
111 changes: 98 additions & 13 deletions max72xx/max72xx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,39 @@ package max72xx

import (
"machine"

"tinygo.org/x/drivers"
)

type Device struct {
bus machine.SPI
bus drivers.SPI
cs machine.Pin
n uint8 // Number of MAX7219 devices in series
}

// NewDriver creates a new max7219 connection. The SPI wire must already be configured
const maxNumberOfDevices = 8

// NewDevice creates a new max7219 connection. The SPI wire must already be configured
// The SPI frequency must not be higher than 10MHz.
// parameter cs: the datasheet also refers to this pin as "load" pin.
func NewDevice(bus machine.SPI, cs machine.Pin) *Device {
func NewDevice(bus drivers.SPI, cs machine.Pin) *Device {
return &Device{
bus: bus,
cs: cs,
n: 1,
}
}

// NewDeviceN creates a new max7219 connection with n devices in series. The SPI wire must already be configured
func NewDeviceN(bus drivers.SPI, cs machine.Pin, n uint8) *Device {
if n < 1 || n > maxNumberOfDevices {
n = 1
}

return &Device{
bus: bus,
cs: cs,
n: n,
}
}

Expand All @@ -31,7 +50,7 @@ func (driver *Device) Configure() {
// SetScanLimit sets the scan limit. Maximum is 8.
// Example: a 4 digit 7SegmentDisplay has a scan limit of 4
func (driver *Device) SetScanLimit(digitNumber uint8) {
driver.WriteCommand(REG_SCANLIMIT, digitNumber-1)
driver.writeToAll(REG_SCANLIMIT, digitNumber-1)
}

// SetIntensity sets the intensity of the diplays.
Expand All @@ -40,7 +59,7 @@ func (driver *Device) SetIntensity(intensity uint8) {
if intensity > 0x0F {
intensity = 0x0F
}
driver.WriteCommand(REG_INTENSITY, intensity)
driver.writeToAll(REG_INTENSITY, intensity)
}

// SetDecodeMode sets the decode mode for 7 segment displays.
Expand All @@ -51,34 +70,34 @@ func (driver *Device) SetIntensity(intensity uint8) {
func (driver *Device) SetDecodeMode(digitNumber uint8) {
switch digitNumber {
case 1: // only decode first digit
driver.WriteCommand(REG_DECODE_MODE, 0x01)
driver.writeToAll(REG_DECODE_MODE, 0x01)
case 2, 3, 4: // decode digits 3-0
driver.WriteCommand(REG_DECODE_MODE, 0x0F)
driver.writeToAll(REG_DECODE_MODE, 0x0F)
case 8: // decode 8 digits
driver.WriteCommand(REG_DECODE_MODE, 0xFF)
driver.writeToAll(REG_DECODE_MODE, 0xFF)
default:
driver.WriteCommand(REG_DECODE_MODE, 0x00)
driver.writeToAll(REG_DECODE_MODE, 0x00)
}
}

// StartShutdownMode sets the IC into a low power shutdown mode.
func (driver *Device) StartShutdownMode() {
driver.WriteCommand(REG_SHUTDOWN, 0x00)
driver.writeToAll(REG_SHUTDOWN, 0x00)
}

// StartShutdownMode sets the IC into normal operation mode.
func (driver *Device) StopShutdownMode() {
driver.WriteCommand(REG_SHUTDOWN, 0x01)
driver.writeToAll(REG_SHUTDOWN, 0x01)
}

// StartDisplayTest starts a display test.
func (driver *Device) StartDisplayTest() {
driver.WriteCommand(REG_DISPLAY_TEST, 0x01)
driver.writeToAll(REG_DISPLAY_TEST, 0x01)
}

// StopDisplayTest stops the display test and gets into normal operation mode.
func (driver *Device) StopDisplayTest() {
driver.WriteCommand(REG_DISPLAY_TEST, 0x00)
driver.writeToAll(REG_DISPLAY_TEST, 0x00)
}

func (driver *Device) writeByte(data byte) {
Expand All @@ -92,3 +111,69 @@ func (driver *Device) WriteCommand(register, data byte) {
driver.writeByte(data)
driver.cs.High()
}

// WriteCommandN sends a command to a specific MAX7219 in the chain
//
// The MAX7219 uses a 16-bit serial protocol divided into two 8-bit segments:
// - The first 8 bits (D15 to D8) represent the address of the register to write to.
// - The second 8 bits (D7 to D0) represent the data to be written to that register.
//
// Register Addresses:
// - 0x00: No-Op Register
// - 0x01 to 0x08: Digit Registers (control individual digits/segments)
// - 0x09: Decode Mode Register (configures decoding mode for digits)
// - 0x0A: Intensity Register (sets brightness level)
// - 0x0B: Scan Limit Register (sets number of digits to display)
// - 0x0C: Shutdown Register (controls shutdown mode)
// - 0x0F: Display Test Register (tests the display)
//
// Examples:
// To set the intensity to a medium level, send the following 16-bit data:
//
// WriteCommandN(0, Command{Register: REG_INTENSITY, Data: 10})
//
// Example: To set digit 1 on the first max72xx to display the number 5 and DP, send the following 16-bit data:
//
// WriteCommandN(0, REG_DIGIT1, 5 | BcdDot})
func (driver *Device) WriteCommandN(deviceNum uint8, register, data byte) {
if deviceNum >= driver.n {
deviceNum = 0
}

tmp := make([]struct {
Register byte
Data byte
}, driver.n)
for i := range tmp {
tmp[i].Register = REG_NOOP
tmp[i].Data = 0x00
}
tmp[deviceNum].Data = data
tmp[deviceNum].Register = register

driver.cs.Low()
for _, d := range tmp {
driver.writeByte(d.Register)
driver.writeByte(d.Data)
}
driver.cs.High()
}

// writeToAll sends the same command to all devices in the chain
func (driver *Device) writeToAll(register, data byte) {
tmp := make([]struct {
Register byte
Data byte
}, driver.n)
for i := range tmp {
tmp[i].Register = register
tmp[i].Data = data
}

driver.cs.Low()
for _, d := range tmp {
driver.writeByte(d.Register)
driver.writeByte(d.Data)
}
driver.cs.High()
}
13 changes: 13 additions & 0 deletions max72xx/registers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,16 @@ const (
REG_SHUTDOWN byte = 0x0C // turn on for no shutdown mode
REG_DISPLAY_TEST byte = 0x0F // turn off for no display test
)

// BCD (B) codes for the 7-segment display
// B coding uses the first 4 bits to represent the character and bit 7 to represent the dot.
// 0 - 9 represent the numbers 0 to 9
const (
BcdDash byte = 10
BcdE byte = 11
BcdH byte = 12
BcdL byte = 13
BcdP byte = 14
BcdBlank byte = 15
BcdDot byte = 128 // 7 bit must be | with the character
)

0 comments on commit efc1302

Please sign in to comment.