[inky] Add Inky Impression 7.3" support
Inky Impression 7.3" is a larger e-ink display that unlike smaller variants is based on AC073TC1A rather than UC8159.
This PR is effectively a port of pimoroni/inky#158 since the difference is primarily in the reset and update commads.
(draft until I have a chance to properly test)
Codecov Report
Attention: Patch coverage is 0% with 141 lines in your changes missing coverage. Please review.
Project coverage is 51.3%. Comparing base (
cad2275) to head (2208b5e). Report is 7 commits behind head on main.
| Files with missing lines | Patch % | Lines |
|---|---|---|
| inky/impression.go | 0.0% | 138 Missing :warning: |
| inky/types.go | 0.0% | 3 Missing :warning: |
:x: Your patch status has failed because the patch coverage (0.0%) is below the target coverage (40.0%). You can increase the patch coverage or adjust the target coverage.
Additional details and impacted files
@@ Coverage Diff @@
## main #75 +/- ##
=======================================
+ Coverage 49.8% 51.3% +1.5%
=======================================
Files 91 102 +11
Lines 11867 13201 +1334
=======================================
+ Hits 5914 6774 +860
- Misses 5695 6135 +440
- Partials 258 292 +34
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
I just saw the PR as it is a draft. Can you fix the linter errors? You'll need to rebase.
@fstanis I updated the PR to the current head of periph.io/devices and addressed a minor lint error.
Did you ever get a chance to test this?
Wow as was actually looking exactly for this :D
Looking forward to be able to use this.
Thanks
Any way I can help to merge this ? I do own the display
Great thanks :)
I think it be only available when a new version has been tagged ? (except if I hardcode the commit during go get)
Hmm I could not make it work so far, I found a few issues so far:
Dev.Bounds() is always (0,0),(0,0), it's not properly set as it should automatically depending on the model (I had to force is via Opts.Height and Opts.Width)
- When Drawing, it would randomly fail with the following logs :
2025/03/02 19:22:47 impression.go:558: Err: bcm283x-gpio (GPIO17): line_request ioctl: bad file descriptor
2025/03/02 19:22:48 impression.go:558: Err: bcm283x-gpio (GPIO17): line_request ioctl: bad file descriptor
2025/03/02 19:22:48 impression.go:558: Err: bcm283x-gpio (GPIO17): line_request ioctl: bad file descriptor
2025/03/02 19:22:48 impression.go:558: Err: bcm283x-gpio (GPIO17): line_request ioctl: bad file descriptor
Which apparently correspond to this : https://github.com/pimoroni/inky/issues/205 But on the python implementation this is not making the drawing fail, those are just warnings, it looks like on the Go implementation this stops the drawing (can't confirm as I can't draw at all)
- When not raising the previous error, it's not actually drawing anything, it does block however the code like if it was indeed drawing something (around 40s)
This is the code I am using: https://github.com/kedare/dashink/blob/main/pkg/hardware/host.go
Thanks
For the size always set to 0,
This is the issue: https://github.com/periph/devices/blob/main/inky/impression.go#L208
It should be this I guess
if o.Width != 0 && o.Height != 0 {
d.width = o.Width
d.height = o.Height
}
@kedare I'm assuming you're using a Raspberry Pi. Is that correct?
Can you tell us what version of periph.io/x/host is listed in your go.mod file? The latest version has updates to the WaitForEdge() calls.
Can you try testing with different pin names? For each required pin, ensure that they are prefixed with "GPIOXX". E.G. for the reset pin, pass "GPIO27".
Yes, I am using a Raspberry Pi Zero 2W, I can use the official python code without problem (just with the warning about busy wait but that is not blocking it from working)
This is what I have in my go.mod
grep periph.io go.mod
periph.io/x/conn/v3 v3.7.2 // indirect
periph.io/x/devices/v3 v3.7.4-0.20250302141124-eb90d535341b // indirect
periph.io/x/host/v3 v3.8.3 // indirect
Tried with the last revision from master, I don't get the logs anymore but same issue.
grep periph.io go.mod
periph.io/x/conn/v3 v3.7.2
periph.io/x/devices/v3 v3.7.4-0.20250302172059-ea55a05aa126
periph.io/x/host/v3 v3.8.4-0.20250117130906-28c0c75f3193
I was using the GPIOxx before but switched to XX as I checked that the code from cmd/inky was doing this. I tried again with GPIOxx but same issue
@kedare Thanks for posting that. The error you're getting seems to be coming out of the GPIO subsystem. Unfortunately, I don't have one of those displays and they're on the expensive side. Just to narrow it down, could you change how you're getting the GPIO pins and see if you're still getting the ioctl errors?
import (
"periph.io/x/host/v3/gpioioctl"
)
func Example() {
_, _ = host.Init()
_, _ = driverreg.Init()
chip := gpioioctl.Chips[0]
fmt.Println(chip.String())
reset:= chip.ByName("GPIO5")
busy:=chip.ByName("GPIO6")
...
Thanks I will try that and let you know
Do you know if there is something like tcpdump that can be used for SPI or GPIO ? I could capture the python run and the go run so we can compare them.
@kedare yes there's http://periph.io/x/conn/v3/gpio/gpiotest#LogPinIO and https://periph.io/x/conn/v3/spi/spitest#Record
I tried with your GPIO method, I am getting the same issue (randomly throwing the error or not throwing the error, when it's not throwing it, it then pause like if it was drawing on the screen but nothing actually happen).
I posted the info there : https://gist.github.com/kedare/dab9dbb19d9d681c514d221e57f63235
Do you want me to setup the gpiotest and spitest thing ?
@kedare Can you report what kernel you're using?
I've looked through the code, and I'm not seeing where the file descriptor is getting closed. Just to confirm the operation of the library, I ran some sample code on a pi zero, and it's working.
I'd like to understand why the file descriptor error is happening. I would be interested in log output of the file descriptor value when errors happen, and don't. It seems like a longshot, but it would confirm things.
If that doesn't offer anything really obvious, I would either run the program under strace and look for the close of the file descriptor, or run it under a debugger and see what I could notice.
FWIW, here's some code that inits and it gets the GPIO IOCTL pins via the bcm283x registration.
package main
import (
"fmt"
"time"
"periph.io/x/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"
"periph.io/x/host/v3"
_ "periph.io/x/host/v3/bcm283x"
"periph.io/x/host/v3/gpioioctl"
)
func main() {
fmt.Println("Calling driverreg.init")
if _, err := driverreg.Init(); err != nil {
fmt.Println("Failed to initialize periph:", err)
return
}
if _, err := host.Init(); err != nil {
fmt.Println("Failed to initialize periph:", err)
return
}
outPin := gpioreg.ByName("GPIO2")
inPin := gpioreg.ByName("GPIO10")
inPin.In(gpio.PullDown, gpio.RisingEdge)
fmt.Printf("inPin=%s, Type: %#v\n", inPin, inPin)
fmt.Printf("outPin=%s Type: %#v\n", outPin, outPin)
go func() {
l := gpio.Low
for {
l = !l
fmt.Println("setting outPin to ", l)
outPin.Out(l)
time.Sleep(1000 * time.Millisecond)
}
}()
for {
if inPin.WaitForEdge(0) {
fmt.Println("Received edge")
} else {
fmt.Println("WaitForEdge() unblocked without receiving edge.")
}
}
}
Output
}
inPin=GPIO10, Type: &bcm283x.Pin{number:10, name:"GPIO10", defaultPull:0x2, ioctlPin:(*gpioioctl.GPIOLine)(0x879b00), usingEdge:true, usingClock:false, dmaCh:(*bcm283x.dmaChannel)(nil), dmaBuf:(*videocore.Mem)(nil)}
outPin=GPIO2 Type: &bcm283x.Pin{number:2, name:"GPIO2", defaultPull:0x3, ioctlPin:(*gpioioctl.GPIOLine)(0x8798c0), usingEdge:false, usingClock:false, dmaCh:(*bcm283x.dmaChannel)(nil), dmaBuf:(*videocore.Mem)(nil)}
setting outPin to High
setting outPin to Low
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
...
This is the kernel I am currently using (on RPI Zero 2W)
Linux 6.6.74+rpt-rpi-v8 #1 SMP PREEMPT Debian 1:6.6.74-1+rpt1 (2025-01-27) aarch64 GNU/Linux
For the strace, I attached one when I don't have the error (but it doesn't draw anything), and one when it give the ioctl error.
trace-no-error.log trace-error.log
Cases happens randomly.
Somehow I had some issues getting the strace, it would hangs up most of the time before even being at the drawing step.
From your code (I just ran it without any change), this is what I get (not sure if this expecting some wiring or manual operation?)
./gpio-test
Calling driverreg.init
inPin=GPIO10, Type: &bcm283x.Pin{number:10, name:"GPIO10", defaultPull:0x2, ioctlPin:(*gpioioctl.GPIOLine)(0x4000180600), usingEdge:true, usingClock:false, dmaCh:(*bcm283x.dmaChannel)(nil), dmaBuf:(*videocore.Mem)(nil)}
outPin=GPIO2 Type: &bcm283x.Pin{number:2, name:"GPIO2", defaultPull:0x3, ioctlPin:(*gpioioctl.GPIOLine)(0x4000180300), usingEdge:false, usingClock:false, dmaCh:(*bcm283x.dmaChannel)(nil), dmaBuf:(*videocore.Mem)(nil)}
setting outPin to High
setting outPin to Low
setting outPin to High
setting outPin to Low
setting outPin to High
setting outPin to Low
setting outPin to High
setting outPin to Low
setting outPin to High
setting outPin to Low
setting outPin to High
setting outPin to Low
setting outPin to High
setting outPin to Low
setting outPin to High
setting outPin to Low
setting outPin to High
setting outPin to Low
@kedare It would need a jumper between GPIO2 and GPIO10 for the edge on inpin to trigger.
Thanks, there you have
❯ ./gpio-test
Calling driverreg.init
inPin=GPIO10, Type: &bcm283x.Pin{number:10, name:"GPIO10", defaultPull:0x2, ioctlPin:(*gpioioctl.GPIOLine)(0x4000100660), usingEdge:true, usingClock:false, dmaCh:(*bcm283x.dmaChannel)(nil), dmaBuf:(*videocore.Mem)(nil)}
outPin=GPIO2 Type: &bcm283x.Pin{number:2, name:"GPIO2", defaultPull:0x3, ioctlPin:(*gpioioctl.GPIOLine)(0x4000100360), usingEdge:false, usingClock:false, dmaCh:(*bcm283x.dmaChannel)(nil), dmaBuf:(*videocore.Mem)(nil)}
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
That's working as expected then. I've got a display on order. If you leave your repo up, I'll take a look. It will take at least a week, I'm sure for it to arrive.