Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ht16k33_alpha: SparkFun pinout support #52

Open
nwf opened this issue Apr 30, 2023 · 0 comments
Open

ht16k33_alpha: SparkFun pinout support #52

nwf opened this issue Apr 30, 2023 · 0 comments

Comments

@nwf
Copy link

nwf commented Apr 30, 2023

Sparkfun also sells their own analogue. However, comparing Adafruit's Schematic and SparkFun's shows that SparkFun has a pretty wildly different wiring diagram, in addition to the slightly different display (rather than Adafruit's 4 decimal points, SparkFun's has one decimal point and one colon).

If you boil away all the C++ in SparkFun's Arduino library for their displays, ignoring the colon and dots, SparkFun's basically turned the frame buffer on its side: the fourteen bits per glyph, which Adafruit packed into two contiguous bytes, are now spread out as two bits in each of seven bytes. In particular, the ith glyph is represented as 0x11 << i, and the framebuffer's 16 bytes are arranged as...

  1. Segments A (0x01) and G2 (0x10)
  2. 0 (or 1 to engage the colon)
  3. Segments B and H
  4. 0 (or 1 to engage the dot)
  5. Segments C and J
  6. 0
  7. Segments D and K
  8. 0
  9. Segments E and L
  10. 0
  11. Segments F and M
  12. 0
  13. Segments G1 and N
  14. 0
  15. 0
  16. 0

If bit-shuffling's your thing, you can map the 16 bits of a font table entry (that is, with segments densely packed from N down to A in the LSB) to the corresponding positions within the 16 * 8 = 2 * 64 = 128-bit framebuffer with something like this wad of Hacker's Delight-esque code (in little-endian representation; big-endian left as an exercise to the reader):

/** Send 0bABCD to 0b0A0B0C0D */
uint32_t nibble_interdigitate_zeros(uint32_t v0) {
  uint32_t v1 = (v0 | (v0 << 2)) & 0x33;  /* 0b00AB00CD */
  return        (v1 | (v1 << 1)) & 0x55;
}

/** Send 0bABCDEFGH to 0b000A000B...000H */
uint32_t byte_interdigitate_three_zeros(uint32_t v0) {
  uint32_t v1 = (v0 | (v0 << 12)) & 0x000F000F;  /* ABCD in top word, EFGH in low word */
  uint32_t v2 = (v1 | (v1 <<  6)) & 0x03030303;  /* AB, CD, EF, GH in successive bytes */
  return        (v2 | (v2 <<  3)) & 0x11111111;
}

/** Send 0xABCDEFGH to 0x00AB00CD00EF00GH */
uint64_t u32_interdigitate_zero_bytes(uint32_t v0) {
  uint64_t v1 = (v0 | (v0 << 16)) & 0x0000FFFF0000FFFF;
  return        (v1 | (v1 <<  8)) & 0x00FF00FF00FF00FF;
}

void mangle(uint16_t c, int glyph, uint64_t *fb) {
  /* Pack segments K D J C H B G2 A into a byte and then expand that byte */
  fb[0] |= u32_interdigitate_zero_bytes(
            byte_interdigitate_three_zeros(
                nibble_interdigitate_zeros((c & 0x000F) >>  0)       /* Segments D C B A */
             | (nibble_interdigitate_zeros((c & 0x0780) >>  7) << 1) /* Segments K J H G2 */
            ) << glyph); /* And shifted left for glyph 0 through 3, and then expanded again */

  /* Do the same thing for segments N G1 M F L E */
  fb[1] |= u32_interdigitate_zero_bytes(
            byte_interdigitate_three_zeros(
                nibble_interdigitate_zeros((c & 0x0070) >>  4)       /* Segments G1 F E */
             | (nibble_interdigitate_zeros((c & 0x3800) >> 11) << 1) /* Segments N M L */
            ) << glyph);

However, I'm not sure how best to handle : and . and how to handle switching between the two display designs. Can the ESPHome machinery generate calls to templatized constructors?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant