{"id":380,"date":"2016-05-12T19:06:48","date_gmt":"2016-05-13T02:06:48","guid":{"rendered":"http:\/\/www.mjblythe.com\/hacks\/?p=380"},"modified":"2021-12-22T00:01:01","modified_gmt":"2021-12-22T07:01:01","slug":"7-segment-driver","status":"publish","type":"post","link":"http:\/\/www.mjblythe.com\/hacks\/2016\/05\/7-segment-driver\/","title":{"rendered":"MAX7219 Seven-segment driver"},"content":{"rendered":"<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2016\/05\/IMG_20160914_200614010-e1473906810526.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2016\/05\/IMG_20160914_200614010-e1473906810526-1024x769.jpg\" alt=\"img_20160914_200614010\" width=\"600\" height=\"450\" class=\"alignleft size-large wp-image-561\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2016\/05\/IMG_20160914_200614010-e1473906810526-1024x769.jpg 1024w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2016\/05\/IMG_20160914_200614010-e1473906810526-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2016\/05\/IMG_20160914_200614010-e1473906810526-768x577.jpg 768w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>I have a couple projects in mind where I want to use a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Seven-segment_display\">seven-segment display<\/a> (one of them where I want <a href=\"http:\/\/www.mjblythe.com\/hacks\/2016\/06\/diy-large-seven-segment-display\/\">large digits<\/a>), but I don&#8217;t want to dedicate too many pins to driving the display. Also, writing custom code to multiplex the digits seemed tedious.<\/p>\n<p>I read about the <a href=\"https:\/\/www.maximintegrated.com\/en\/products\/power\/display-power-control\/MAX7219.html\">MAX7219<\/a> chip, which lets you drive up to 8 digits over SPI, and it seemed to be just what I was looking for.<\/p>\n<p><!--more--><\/p>\n<p>You can buy this part from <a href=\"https:\/\/www.sparkfun.com\/products\/9622\">the<\/a> <a href=\"https:\/\/www.adafruit.com\/product\/453\">usual<\/a> <a href=\"http:\/\/www.digikey.com\/product-detail\/en\/maxim-integrated\/MAX7219CNG-\/MAX7219CNG--ND\/948191\">suspects<\/a>, but I also found that Maxim offers engineering samples.<\/p>\n<p>While I was working on this, the following datasheets were incredibly helpful:<\/p>\n<ul>\n<li><a href=\"https:\/\/cdn-shop.adafruit.com\/datasheets\/MAX7219.pdf\">MAX7219<\/a><\/li>\n<li><a href=\"https:\/\/cdn-shop.adafruit.com\/datasheets\/BL-Q39A-42.PDF\">the 7-segment display I used<\/a><\/li>\n<li><a href=\"http:\/\/www.atmel.com\/Images\/Atmel-2545-8-bit-AVR-Microcontroller-ATmega48-88-168_datasheet.pdf\">ATmega168<\/a> (I think it used to be <a href=\"http:\/\/www.atmel.com\/images\/doc2545.pdf\">here<\/a>, but that&#8217;s a dead link now)<\/li>\n<\/ul>\n<p>&#8230;And here it is, all wired up!<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2016\/05\/IMG_20160914_200701704-1-e1473908152890.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2016\/05\/IMG_20160914_200701704-1-e1473908152890-1024x771.jpg\" alt=\"img_20160914_200701704\" width=\"600\" height=\"450\" class=\"alignleft size-large wp-image-566\" \/><\/a><\/p>\n<p>As with any project, this one was fraught with roadblocks, mis-steps, and stumbles that needed to be debugged and addressed.<\/p>\n<h3>1) Apparently, I don&#8217;t know how to program my board anymore.<\/h3>\n<p>When I tried to flash my board, I was greeted by the following wonderfully descriptive error messsage:<\/p>\n<blockquote><p><code>Connecting to programmer: .avrdude: butterfly_recv(): programmer is not responding<\/code><\/p><\/blockquote>\n<p>I hadn&#8217;t programmed this board since I updated my computer to Xubuntu 15.10, and something obviously changed. I found <a href=\"http:\/\/www.nerdkits.com\/forum\/thread\/2446\/\">this forum thread<\/a> that indicated I needed to split the <code>avrdude<\/code> command into two commands, and add a small delay between them:<\/p>\n<blockquote>\n<pre>\r\n%-upload: %.hex\r\n        avrdude ${AVRDUDEFLAGS} -e\r\n        sleep 0.1\r\n        avrdude ${AVRDUDEFLAGS} -D -U flash:w:$<:a\r\n<\/pre>\n<\/blockquote>\n<p>That fixed it!<\/p>\n<h3>2) It helps to call the code you write<\/h3>\n<p>I had coded up a function to configure the SPI block...but it turns out you actually need to call the function in order for it to do anything...duh! While I was trying to figure out where I went wrong, I found <a href=\"http:\/\/maxembedded.com\/2013\/11\/the-spi-of-the-avr\/\">this incredibly useful blog post<\/a>.\u00a0 Of course, none of the tweaks that it lead me to make had any effect until I actually called the function.<\/p>\n<h3>3) Infinite loop of resets<\/h3>\n<p>Another no-no...don't enable interrupts unless you have the proper ISRs in place, otherwise your chips just resets over &amp; over.<\/p>\n<h3>4) It's all zeroes<\/h3>\n<p>In retrospect, it makes sense, but at the time I hadn't realized it...all registers on the driver chip initialize to 0.\u00a0 This means that it starts up in shutdown mode.\u00a0 Once you enable that, it's really dim because it's set to the minimum intensity.\u00a0 And once you get it brighter, it doesn't actually show digits because the digit decode mode is disabled!<\/p>\n<h3>5) It's all ones<\/h3>\n<p>Once I got all the display registers set correctly, I found that non-decode mode (i.e. each bit controls a segment directly) wasn't working...why? Specifically, all the segments were always lit, as if I was loading all-ones into my pattern array.\u00a0 I was trying to write a \"spinning\" pattern, not all-on.<\/p>\n<p>I worked through lots of stuff...I was convinced that it was a problem with how I was initializing my pattern array:<\/p>\n<blockquote>\n<pre>uint8_t patterns[] =\r\n  { 0b00111110,\r\n    0b01011110,\r\n    0b01101110,\r\n    0b01110110,\r\n    0b01111010,\r\n    0b01111100 };<\/pre>\n<\/blockquote>\n<p>When I manually initialized the array in main() (i.e. <code>patterns[0] = 0x3e;<\/code> etc.), it worked as expected, so I was convinced I had something wrong with this code!<\/p>\n<p>I thought maybe it was because I was using C99 syntax, or that the #define I was using for that \"0b\" syntax was wrong, or something.\u00a0 I don't even remember how many times I changed that piece of code.<\/p>\n<p>No, it's actually that my array initialization doesn't work.\u00a0 After much googling, I finally found the solution on a <a href=\"http:\/\/electronics.stackexchange.com\/questions\/60109\/avr-gcc-global-static-array-not-getting-initialized-properly\">StackExchange thread<\/a> (which linked to an <a href=\"http:\/\/www.avrfreaks.net\/comment\/893625#comment-893625\">avrfreaks thread<\/a>).<\/p>\n<p>My <code>avr-objcopy<\/code> command only had <code>-j .text<\/code>, but it needed <code>-j .text -j .data<\/code>.\u00a0 Apparently, the array init stuff is in the <code>.data<\/code> section, which also needs to be copied into the hex file that's loaded.<\/p>\n<h3>It's alive!<\/h3>\n<p>Finally, after I worked through the last issue, and it worked as intended!<\/p>\n<p><video width=\"600\" height=\"338\" autoplay loop><source src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2016\/05\/MAX7219.mp4\" type=\"video\/mp4\" \/><\/video><\/p>\n<p>I also ported the code to the ESP8266 (programmed via the Arduino IDE).<\/p>\n<p><video width=\"600\" height=\"338\" autoplay loop><source src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2016\/05\/MAX7219_ESP8266.mp4\" type=\"video\/mp4\" \/><\/video><\/p>\n<p>The code for both of these microcontrollers can be found on <a href=\"https:\/\/github.com\/mblythe86\/MAX7219\">my github page<\/a>.<\/p>\n<hr>\n","protected":false},"excerpt":{"rendered":"<p>I have a couple projects in mind where I want to use a seven-segment display (one of them where I want large digits), but I don&#8217;t want to dedicate too many pins to driving the display. Also, writing custom code to multiplex the digits seemed tedious. I read about the MAX7219 chip, which lets you [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[7,15],"tags":[],"class_list":["post-380","post","type-post","status-publish","format-standard","hentry","category-howto","category-trial-and-error"],"_links":{"self":[{"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/posts\/380","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/comments?post=380"}],"version-history":[{"count":20,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/posts\/380\/revisions"}],"predecessor-version":[{"id":573,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/posts\/380\/revisions\/573"}],"wp:attachment":[{"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/media?parent=380"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/categories?post=380"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/tags?post=380"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}