Help add support for HT1632 in u8glib

It would be nice to have support for the HT1632 LED matrix panels in a graphics library. Can someone help code the device description for the u8glib library?

Some initial work (along with the appropriate datasheets) has been done here: https://code.google.com/p/u8glib/issues/detail?id=165

Unluckily I lack the proper skills to completely do this myself, I'm posting to raise awareness. I'm pretty sure someone else will also find it interesting. Tips and/or some code help will be extremely helpful.

Thanks!

Hi

I was in contact with a user of u8glib, but unfortunately the communication seems the be stopped. I was waiting for the user to provide the low level procedures for the u8glib device:
http://code.google.com/p/u8glib/source/browse/csrc/u8g_dev_ht1632_26x16.c

I would be glad to add such support to u8glib, but i need someone to

  • provide low level procedures
  • do the testing

My part will be

  • create u8glib devices
  • create beta releases
  • add documentation

Oliver (u8glib)

What low-level functions do you need? There are some functions posted on Google Code and I assume they are used for data transfer.

Well, the following two procedures need to be filled with some suitable code. For sure this will require some low level transfer functions also. I do not now if there is some need to send an init sequence. If not, then ht1632_init might be empty. The procedure ht1632_transfer_data receives data from u8glib and shoud transfer this data to the display. Are you able to provide such code? What additional information do you need?

void ht1632_init(void)
{
  /* init display once after startup */
}

/*
  page: 0=data contain lines 0..7, 1=data contain lines 8..16
  cnt: number of bytes in the buffer
  data: pointer to a buffer with "cnt" bytes.
*/
void ht1632_transfer_data(uint8_t page, uint8_t cnt, uint8_t *data)
{
  /* send data to the ht1632 */
}

Oliver

I'll share all the information I can. Ask me anything you need and I'll try to help you. Thanks for looking into this!

This is the command-set of the chip. There are more commands available but aren't used. Some of those commands are also not used but can be deleted after the driver is implemented. There are also definitions for command and data sizes.

#define HT1632_CMD_SYSDIS	0x00	// CMD= 0000-0000-x Turn off oscil
#define HT1632_CMD_SYSON	0x01	// CMD= 0000-0001-x Enable system oscil
#define HT1632_CMD_LEDOFF	0x02	// CMD= 0000-0010-x LED duty cycle gen off
#define HT1632_CMD_LEDON	0x03	// CMD= 0000-0011-x LEDs ON
#define HT1632_CMD_BLOFF	0x08	// CMD= 0000-1000-x Blink OFF
#define HT1632_CMD_BLON		0x09	// CMD= 0000-1001-x Blink On
#define HT1632_CMD_SLVMD	0x10	// CMD= 0001-00xx-x Slave Mode
#define HT1632_CMD_MSTMD	0x14	// CMD= 0001-01xx-x Master Mode
#define HT1632_CMD_RCCLK	0x18	// CMD= 0001-10xx-x Use on-chip clock
#define HT1632_CMD_EXTCLK	0x1C	// CMD= 0001-11xx-x Use external clock
#define HT1632_CMD_COMS00	0x20	// CMD= 0010-ABxx-x commons options
#define HT1632_CMD_COMS01	0x24	// CMD= 0010-ABxx-x commons options
#define HT1632_CMD_COMS10	0x28	// CMD= 0010-ABxx-x commons options
#define HT1632_CMD_COMS11	0x2C	// P-MOS OUTPUT AND 16COMMON OPTION
#define HT1632_CMD_PWM		0xA0	// CMD= 101x-PPPP-x PWM duty cycle

#define HT1632_ID_LEN		3		// IDs are 3 bits
#define HT1632_CMD_LEN		8		// CMDs are 8 bits
#define HT1632_DATA_LEN		8		// Data are 4*2 bits
#define HT1632_ADDR_LEN		7		// Address are 7 bits

This is the initialization sequence for the chip.

writeDataMSB(3, HT1632_ID_CMD, false); // IDs are 3 bits
writeDataMSB(8, HT1632_CMD_SYSDIS, true); // 8 bits
writeDataMSB(8, HT1632_CMD_SYSON, true); // 8 bits
writeDataMSB(8, HT1632_CMD_COMS11, true); // 8 bits
writeDataMSB(8, HT1632_CMD_LEDON, true); // 8 bits
writeDataMSB(8, HT1632_CMD_BLOFF, true); // 8 bits
writeDataMSB(8, HT1632_CMD_PWM+15, true); // 8 bits

This function writes IDs and command data into the display:

void writeDataMSB(byte cnt, byte data, bool extra) {
	for(int8_t i = cnt - 1; i >= 0; i--) {
		if ((data >> i) & 1) {
			PORT |= 1 << DATA;
		}
		else {
			PORT &= ~(1 << DATA);
		}
		//_nop();
		PORT &= ~(1 << WR);
		//_nop();
		PORT |= 1 << WR;
		//_nop();
    }

	// Send an extra bit
	if (extra) {
		PORT |= 1 << DATA;
		//_nop();
		PORT &= ~(1 << WR);
		//_nop();
		PORT |= 1 << WR;
	}
}

This function writes pixel data onto the display (after the appropriate command has been set):

void write_data(byte cnt, byte data) {
	for (byte i = 0; i < cnt; i++) {
		if ((data >> i) & 1) {
			PORT |= 1 << DATA;
		}
		else {
			PORT &= ~(1 << DATA);
		}

		PORT &= ~(1 << WR);
		PORT |= 1 << WR;
	}
}

PORT is the AVR port. DATA is the data pin and WR is the clock pin. Those should be changed to be set by u8glib I guess.

This code is used to write pixel data from a framebuffer:

selectDisplay(dispNum); // selects the display

writeDataMSB(3, HT1632_ID_WR); // Send "write to display" command
writeDataMSB(7, 0); // Send initial address (aka 0)

// Operating in progressive addressing mode
for (uint8_t addr = 0; addr < FB_SIZE; addr++) { // FB_SIZE is 48 bytes
	value = framebuffer[addr];
	writeDataLSB(8, value);  
}

releaseDisplay(dispNum);

I hope that helps!

writeDataLSB(8, value);

Is this the write_data() procedure?

Oliver

Yes, it writes the data to the chip in LSB

EDIT: I mean the display data!

I have some other issues with the code.
ID values are missing. I assume

#define HT1632_ID_CMD	0x04
#define HT1632_ID_WR	0x05

Then: You used

writeDataMSB(3, HT1632_ID_WR); // Send "write to display" command
writeDataMSB(7, 0); // Send initial address

but writeDataMSB() requires three arguments. What will be the third argument?

Oliver

I have integrated your code:

http://code.google.com/p/u8glib/source/browse/csrc/u8g_dev_ht1632_26x16.c

Maybe you can do a code review.
Pin numbers are hard coded at the moment.

I have also attached a new u8glib release, including the updated code. However in the past attachments to the forum seem to be currupted.

Example .ino is:

#include "U8glib.h"

void setup(void)
{
}

void loop(void)
{
  u8g_t u8g;
  
  u8g_Init(&u8g, &u8g_dev_ht1632_26x16);
  u8g_FirstPage(&u8g);
  u8g_SetColorIndex(&u8g, 1);
  do  {
    u8g_SetFont(&u8g, u8g_font_7x13);
    u8g_DrawStr(&u8g, 0, 14, "ABCgdef");
  }while( u8g_NextPage(&u8g) );
  delay(1000);
}

Can you test the new code?

Oliver

u8glib_arduino_v1.13pre4.zip (1020 KB)

olikraus:
I have some other issues with the code.
ID values are missing. I assume

#define HT1632_ID_CMD	0x04

#define HT1632_ID_WR 0x05

Oops! I forgot to include them!

#define HT1632_ID_CMD	4	/* ID = 100 - Commands */
#define HT1632_ID_RD	6	/* ID = 110 - Read RAM */
#define HT1632_ID_WR	5	/* ID = 101 - Write RAM */

olikraus:
Then: You used

writeDataMSB(3, HT1632_ID_WR); // Send "write to display" command

writeDataMSB(7, 0); // Send initial address



but writeDataMSB() requires three arguments. What will be the third argument?

Oliver

This is how the signature of the procedure:

void writeDataMSB(byte cnt, byte data, bool extra = false);

I will test the code as soon as possible! Thanks a lot!

EDIT: One last thing! u8g_dev_ht1632_26x16.c should be u8g_dev_ht1632_24x16.c! The panel is 24x16!

EDIT: One last thing! u8g_dev_ht1632_26x16.c should be u8g_dev_ht1632_24x16.c! The panel is 24x16!

Oh, ok, I have renamed the device. For testing you also should restrict the WIDTH to 24.

Oliver

I did test the code but unfortunately it doesn't work. I did a quick review but I couldn't spot anything wrong. I will check later when I have more time. A quick question: Where does ht1632_init gets called? Shouldn't it be inside U8G_DEV_MSG_INIT?

Where does ht1632_init gets called? Shouldn't it be inside U8G_DEV_MSG_INIT?

Yes, indeed. It seems that i missed calling tins procedure.

Oliver

I fixed that myself but didn't make any difference. How can I start debugging this?

Did you update the Arduino Pin Numbers?
Debuggung: I usually start by expanding the init sequence to output some test pattern.

Oliver

Yes I did. I moved out the communication specific parts to a seperate sketch and I'm doing tests. I am trying to fill the display with data (fill the whole LED RAM). Something is broken and only three columns light up, but I hope I'll sort this out really soon!

Success! I have a complete sketch and I am able to send data on the display.

This is the working sketch, it flashes the screen on and off: #define HT1632_CMD_SYSDIS 0x00 // CMD= 0000-0000-x Turn off oscil#define HT163 - Pastebin.com

I have implemented the changes in my copy of u8glib but had no success in making it work. First of all, I did this change as we discussed:

[...]
switch(msg)
  {
    case U8G_DEV_MSG_INIT:
		ht1632_init();
      break;
    case U8G_DEV_MSG_STOP:
      break;
[...]

To make sure that everything is ok, I changed the ht1632_init() procedure to:

void ht1632_init(void)
{
  digitalWrite(CS_PIN, LOW);
  /* init display once after startup */
  ht1632_write_data_MSB(3, HT1632_ID_CMD, false); // IDs are 3 bits
  ht1632_write_data_MSB(8, HT1632_CMD_SYSDIS, true); // 8 bits
  ht1632_write_data_MSB(8, HT1632_CMD_SYSON, true); // 8 bits
  ht1632_write_data_MSB(8, HT1632_CMD_COMS11, true); // 8 bits
  ht1632_write_data_MSB(8, HT1632_CMD_LEDON, true); // 8 bits
  ht1632_write_data_MSB(8, HT1632_CMD_BLOFF, true); // 8 bits
  ht1632_write_data_MSB(8, HT1632_CMD_PWM+15, true); // 8 bits  
  digitalWrite(CS_PIN, HIGH);

  // Fill the screen
  // #######################################
  digitalWrite(CS_PIN, LOW);
  ht1632_write_data_MSB(3, HT1632_ID_WR, false); // Send "write to display" command
  ht1632_write_data_MSB(7, 0, false);
  uint8_t i;
  for(i = 0; i<48; ++i)
  {
    ht1632_write_data(8,0xFF);
  }
  digitalWrite(CS_PIN, HIGH);
  // #######################################
}

I also did made change to the sketch in order to have only to invoke only the init function:

void loop(void)
{
  u8g_t u8g;
  
  u8g_Init(&u8g, &u8g_dev_ht1632_26x16);
  /*u8g_FirstPage(&u8g);
  u8g_SetColorIndex(&u8g, 1);
  do  {
    u8g_SetFont(&u8g, u8g_font_7x13);
    u8g_DrawStr(&u8g, 0, 14, "ABCgdef");
  }while( u8g_NextPage(&u8g) );*/
  delay(1000);
}

What should I do now?

what happens if you uncomment your draw procedure?
You should also move the init procedure into setup():

u8g_t u8g;
  
void setup(void) {
  u8g_Init(&u8g, &u8g_dev_ht1632_26x16);
}

void loop(void) {
  u8g_FirstPage(&u8g);
  u8g_SetColorIndex(&u8g, 1);
  do  {
    u8g_SetFont(&u8g, u8g_font_7x13);
    u8g_DrawStr(&u8g, 0, 14, "ABCgdef");
  }while( u8g_NextPage(&u8g) )
  delay(1000);
}

This is my current sketch:

#include "U8glib.h"

u8g_t u8g;

void setup(void)
{
  u8g_Init(&u8g, &u8g_dev_ht1632_26x16);
}

void loop(void)
{
  u8g_FirstPage(&u8g);
  u8g_SetColorIndex(&u8g, 1);
  do  {
    //u8g_SetFont(&u8g, u8g_font_7x13);
    //u8g_DrawStr(&u8g, 0, 14, "ABCgdef");
  }while( u8g_NextPage(&u8g) );
  delay(1000);
}

I am sure that the init procedure is called. I placed digitalWrite(13, HIGH) on the first and the LED lights up. It not bright as it should, for some reason it's dim. EDIT: Something might be using the SPI port on u8glib. I uploaded the Blink example and it's bright as it should. I don't have anything connected on pin 13.

Nothing is shown on the display. I still have my custom code to fill the graphics RAM (like my test sketch).

EDIT2:
Minor success! I'm not getting the full RAM filled again but I'm looking into it. That's what was missing.

  pinMode(DATA_PIN, OUTPUT);
  pinMode(WR_PIN, OUTPUT);
  pinMode(CS_PIN, OUTPUT);

  digitalWrite(DATA_PIN, HIGH);
  digitalWrite(WR_PIN, HIGH);
  digitalWrite(CS_PIN, HIGH);

New post because my last one is a mess. I finally got it working! Data is being sent. After init finishes the whole display is lit up. When I uncomment the do statement (not the contents, just the statement) about half of the screen turns black. If I uncomment the contents of the screen garbage is written on the cleared part.