| Author |
Message |
|
|
Posted: Apr 18, 2010 - 05:07 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
hi everyone i'm new so if i have put this in the wrong place i'm sorry.
i am currently working on a project, and i am trying to get some numbers output on 8 7-segment displays. the displays are driven by a Maxim max7219 chip. i have PIN.B0, on the Atmega 16 connected to the DIN pin of the 7219, B1 connected to LOAD and B2 connected to CLK.
my question is how do i code the program to output the numbers to the the 7-segment displays?
I'm using AVR studio 4 with WinAVR.
also if the connections are wrong or there needs to be additional connections that advice would be greatly appreciated. |
|
|
| |
|
|
|
|
|
Posted: Apr 18, 2010 - 05:32 AM |
|


Joined: Nov 22, 2002
Posts: 12031
Location: Tangent, OR, USA
|
|
I assume that your "b1" refers to I/O pin PB1 on the AVR.
This chip communicates via SPI, so you want to use the hardware SPI port. That would be PB4-PB7 on the Mega16.
It takes TWO of these chips, a 7219 and and a 7221 to drive multiple digits. For one digit, you can use a 7221, only. I don't see how you would use a 7219, by itself. The 7219 is a "digit selector" and the 7219 is the "segment selector".
Jim |
_________________ Jim Wagner
Oregon Research Electronics, Consulting Div.
Tangent, OR, USA
"The only thing standing between us and victory is defeat" P.G.Wodhouse in Wooster & Jeeves series
|
| |
|
|
|
|
|
Posted: Apr 18, 2010 - 06:00 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
| the way i was told it works is the 7219 only enables one digit at a time but if the cycle rate is high enough it looks like it is driving all 8 digits at once. |
|
|
| |
|
|
|
|
|
Posted: Apr 18, 2010 - 07:31 AM |
|


Joined: Nov 22, 2002
Posts: 12031
Location: Tangent, OR, USA
|
|
You have the principle right, but not the detail.
Yes, 7219 enables one digit at a time. BUT, you are talking about starting with only one digit. So, you have to enable various SEGMENTS of that digit in order to create various symbols. Thus, for this one digit, you need a 7221 to control the segments of that digit.
Now, the way the whole thing works. You send the serial data to a 7221 to turn on various digits for the first character. Then you send data to the 7219 to turn on the digit for the segments you just enabled. That turns on the display digit. Then, strictly, you would send a new message to the 7219 to turn off the digit that was just on. THen you send the message to the 7221 to turn on the desired segments of the second digit. Then you send the data to the 7219 to turn on just that digit. You then continue this pattern until all digits have been displayed and THEN you start over.
Each of the "messages" (data) to a 7219 or 7221 goes out the SPI port. You enable the desired chip, then send the 8 bits to achieve the desired operation,
Hope this helps
Jim |
_________________ Jim Wagner
Oregon Research Electronics, Consulting Div.
Tangent, OR, USA
"The only thing standing between us and victory is defeat" P.G.Wodhouse in Wooster & Jeeves series
|
| |
|
|
|
|
|
Posted: Apr 18, 2010 - 10:58 AM |
|

Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England
|
|
Jim is over complicating it.
You have the MAX7219 connected to a load of 7 segment displays according to the schematic in the data sheet.
Then you just write 16 bit command words to the MAZ7219. The multiplexing, brightness, display contents etc are all determined by the commands that you give it.
Then it will continue to do everything by itself. Just like a Computer terminal. You type -- it displays. You can still read the display days later. Unless you type something different.
Since you are not using the official SPI pins, you will need to bit-bash the 16 bit command words.
Code:
#define SDP8_CLOCK (1<<2)
#define SDP8_LOAD (1<<1)
#define SDP8_DATA (1<<0)
#define DDR_WRITE 0x07 /* bits 0-2 o/p */
#define sdp8_data PORTB
#define sdp8_ctl DDRB
static void shft8bit(unsigned char val)
{
unsigned char cnt;
sdp8_data &= (~SDP8_CLOCK & ~SDP8_LOAD); /* CLOCK = LOAD = 0 */
for (cnt = 8; cnt; --cnt, val <<= 1) {
sdp8_data &= ~SDP8_DATA;
if (val & 0x80) sdp8_data |= SDP8_DATA;
sdp8_data |= SDP8_CLOCK;
sdp8_data &= ~SDP8_CLOCK;
}
sdp8_data |= SDP8_DATA;
}
void sdp8(unsigned char posn, unsigned char val)
{
shft8bit(posn);
shft8bit(val);
sdp8_data |= SDP8_LOAD;
sdp8_data &= ~SDP8_LOAD;
}
void initsdp8(void)
{
sdp8_ctl = DDR_WRITE;
sdp8(0x0a, 0x01); /* low intensity */
sdp8(0x0b, 0x07); /* scan limit */
sdp8(0x09, 0xff); /* decode each digit */
sdp8(0x0c, 0x01); /* not shutdown */
sdp8(0x0f, 0x00); /* display test */
}
Each 16 bit word is made up with the 8 bit 'command' and the 8 bit 'argument'. Once you have done the initialising, you just write to position 1..8 and it will display data in that 7-seg.
If you write 0x00 for command #9, it will do the decoding for you.
Code:
sdp8(0x09, 0x00); /* automatic decode */
e.g. you just write the raw data to each digit
Code:
// show 567
sdp8(0x01, 0x05); /* */
sdp8(0x02, 0x06); /* */
sdp8(0x03, 0x07); /* */
David. |
|
|
| |
|
|
|
|
|
Posted: Apr 19, 2010 - 01:58 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
| would it be simpler to just move the connections to the official SPI pins as they are not being used by anything at the moment? |
|
|
| |
|
|
|
|
|
Posted: Apr 19, 2010 - 02:08 AM |
|


Joined: Nov 22, 2002
Posts: 12031
Location: Tangent, OR, USA
|
|
Absolutely!
Jim |
_________________ Jim Wagner
Oregon Research Electronics, Consulting Div.
Tangent, OR, USA
"The only thing standing between us and victory is defeat" P.G.Wodhouse in Wooster & Jeeves series
|
| |
|
|
|
|
|
Posted: Apr 20, 2010 - 02:21 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
Ok with the SPI all i need to do is use the code in the ATmega16's data sheet and it should be capable of transmitting a 16-bit word to the 7219, is that right or is there more i need to do?
Thanks for the help
Code:
void SPI_MasterInit(void)
{
/* Set MOSI and SCK output, all others input */
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);
/* Enable SPI, Master, set clock rate fck/16 */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
void SPI_MasterTransmit(char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
}
|
|
|
| |
|
|
|
|
|
Posted: Apr 20, 2010 - 04:40 AM |
|


Joined: Mar 28, 2001
Posts: 20311
Location: Sydney, Australia (Gum trees, Koalas and Kangaroos, No Edelweiss)
|
|
|
Quote:
should be capable of transmitting a 16-bit word
No such thing with SPI, all transactions happen 8 bit at a time. So you will need to spit the 16 bit word into 2, send the first byte, wait for SPIF (as above) send 2nd byte. |
_________________ John Samperi
Ampertronics Pty. Ltd.
www.ampertronics.com.au
* Electronic Design * Custom Products * Contract Assembly
|
| |
|
|
|
|
|
Posted: Apr 20, 2010 - 05:39 AM |
|

Joined: May 24, 2004
Posts: 5994
Location: Tampere, Finland
|
|
|
baker158 wrote:
Ok with the SPI all i need to do is use the code in the ATmega16's data sheet and it should be capable of transmitting a 16-bit word to the 7219, is that right or is there more i need to do?
Thanks for the help
You need to control the chip select or load too yourself. Also with proper timing related to bytes. SPI hardware only transmits 8-bit bytes via clock and data pins. So a 16-bit word is two bytes. |
|
|
| |
|
|
|
|
|
Posted: Apr 20, 2010 - 09:29 AM |
|

Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England
|
|
I showed a bit-bash solution because the OP said he was using non-SPI lines.
However if you use SPI lines yo just use:
Code:
void sdp8(unsigned char posn, unsigned char val)
{
sdp8_data &= ~SDP8_LOAD; // enable SPI
spi(posn);
spi(val);
sdp8_data |= SDP8_LOAD; // latch the data
}
Note that the MAX7219 happily reads in whatever you send it. However it only latches the information when the 'LOAD' pin goes high. ( /SS going high )
If you cascade several MAX7219's you propagate the relevant 16 bit command to each MAX7219 in the chain. As /SS goes high, the command is latched and the display is updated accordingly.
Oh, for those people who find difficulty with a 16 bit command: 16 bits is two times 8 bits.
David. |
|
|
| |
|
|
|
|
|
Posted: May 14, 2010 - 07:28 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
ok i've been trying to get this to work, below shows the connections between the atmega16 and max7219
atmega-max7219
PB0-LOAD
PB5(MOSI)-DIN
PB7(SCK)-CLK
below is the code i am using, it should just be displaying the test function of the max7219 but i get nothing on the 7-segment display.
Code:
#include <avr/io.h>
#define SDP8_LOAD (1<<0)
#define sdp8_data PORTB
#define sdp8_ctl DDRB
void SPI_MasterInit(void)
{
/* Set MOSI and SCK and B0 (B0 is load pin) output, all others input */
DDRB = (1<<DDB5)|(1<<DDB7)|(1<<DDB0);
/* Enable SPI, Master, set clock rate fck/16 */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
void spi(char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
;
}
void sdp8(unsigned char posn, unsigned char val)
{
sdp8_data &= ~SDP8_LOAD; // enable SPI
spi(posn);
spi(val);
PORTB|=0b00000001; // latch the data
}
void initsdp8(void)
{
// sdp8_ctl = DDR_WRITE;
sdp8(0x0A, 0x01); /* low intensity */
sdp8(0x0B, 0x00); /* scan limit set to digit 0 only, 0x07 for all digits*/
sdp8(0x09, 0x01); /* decode digit 0 (FF for decode all digits)*/
sdp8(0x0C, 0x01); /* not shutdown */
sdp8(0x0F, 0x01); /* display test */
// _delay_ms(100); /*display test for 1 second*/
// sdp8(0x0F, 0x00); /* stop test*/
}
int main(void)
{
initsdp8();
}
are there any problems? what is the likely hood that the max7219 is fried? and is there any way of testing it its fried apart from writing a program as above?
Thanks for the help. |
|
|
| |
|
|
|
|
|
Posted: May 14, 2010 - 08:25 AM |
|

Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England
|
|
Your code should work. I would be happier with you driving 8 displays even if you only have one connected.
After all, if you have the wrong display selected, you will not see anything.
So wire up your hardware according to the schematic in the 7219 data sheet. And display the test on all displays.
David. |
|
|
| |
|
|
|
|
|
Posted: May 15, 2010 - 12:04 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
ok it works but only when i enable the test feature
Code:
sdp8(0x0F,0x01)
i get nothing with the following code which should output a number to the display depending on which digit of the 7219 the 7-segment display is connected to.
for reference i know it is connected to Digit0 but i still get nothing.
Code:
void initsdp8(void)
{
sdp8(0x0A, 0x0F); /* high intensity */
sdp8(0x0B, 0x07); /* scan limit set to digit 0 only, 0x07 for all digits*/
sdp8(0x09, 0xFF); /* decode digit 0 (FF for decode all digits)*/
sdp8(0x0C, 0x01); /* not shutdown */
//sdp8(0x0F, 0x01); /* display test */
//_delay_ms(1000); /*display test for 1 second*/
sdp8(0x0F, 0x00); /* stop test*/
}
int main(void)
{
initsdp8();
while(1)
{
sdp8(0x01, 0x01);
sdp8(0x02, 0x02);
sdp8(0x03, 0x03);
sdp8(0x04, 0x04);
sdp8(0x05, 0x05);
sdp8(0x06, 0x06);
sdp8(0x07, 0x07);
sdp8(0x08, 0x08);
}
return 1;
}
thanks again for the help |
|
|
| |
|
|
|
|
|
Posted: May 15, 2010 - 08:04 AM |
|

Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England
|
|
Your code should display '12345678' or possibly '87654321'.
IME maximum intensity takes a LOT of current.
David. |
|
|
| |
|
|
|
|
|
Posted: May 16, 2010 - 05:59 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
|
david.prentice wrote:
Your code should display '12345678' or possibly '87654321'.
IME maximum intensity takes a LOT of current.
David.
thats true is should be displaying all those numbers but if i only have one 7-segment display connected shouldn't it only display the number that is being sent to that display?
ie. if i only have one 7-segment display which is connected to Digit0 on the 7219 then it should be showing 1 on that display and then be sending the other numbers to the other digits that are not connected.
I'll turn the intensity down
thanks for the help |
|
|
| |
|
|
|
|
|
Posted: Jun 21, 2010 - 10:41 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
ok i've finally got some time to work on this.
I have changed from a MAX7219 to a MAX7221, all other hardware is the same and the connections can be seen in the attachment.
i am trying to send the number 6 to digit 1 on the MAX7221, or any number for that matter.
the code i'm using is
Code:
#include <avr/io.h>
#include <util/delay.h>
#define SDP8_LOAD (1<<0)
#define sdp8_data PORTB
#define sdp8_ctl DDRB
void SPI_MasterInit(void)
{
/* Set MOSI and SCK and B0 (B0 is load pin) output, all others input */
DDRB = (1<<DDB5)|(1<<DDB7)|(1<<DDB0);
/* Enable SPI, Master, set clock rate fck/16 */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
void spi(unsigned char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
;
}
void sdp8(unsigned char posn, unsigned char val)
{
PORTB &= ~0b00000001; // enable SPI
spi(posn);
spi(val);
PORTB|=0b00000010; // latch the data
}
void initsdp8(void)
{
sdp8(0x0A, 0x07); /* high intensity */
sdp8(0x0B, 0x07); /* scan limit set to digit 0 only, 0x07 for all digits*/
sdp8(0x09, 0xFF); /* no decode (FF for decode all digits)*/
sdp8(0x0C, 0x01); /* not shutdown */
sdp8(0x0F, 0x00); /* stop test*/
}
int main(void)
{
initsdp8();
sdp8(0x01, 0x06);
}
my question is, is there anything wrong with the setup or code?
currently i can only get the 7-segment display to intermittently light up and when it does it's either erratic or simply lights up all segments.
any help would be greatly appreciated. |
|
|
| |
|
|
|
|
|
Posted: Jun 21, 2010 - 10:57 AM |
|

Joined: Feb 12, 2005
Posts: 16254
Location: Wormshill, England
|
|
Your /CS is on PORTB.1 according to your schematic. So you should have:
Code:
...
DDRB = (1<<DDB5)|(1<<DDB7)|(1<<DDB1);
...
void sdp8(unsigned char posn, unsigned char val)
{
PORTB &= ~(1<<PB1); // enable SPI
spi(posn);
spi(val);
PORTB |= (1<<PB1); // latch the data
}
Personally, I would prefer to use the macros:
Code:
#define SDP8_LOAD (1<<PB1) // PORTB.1
...
...
DDRB = (1<<DDB5)|(1<<DDB7)|SDP8_LOAD;
...
void sdp8(unsigned char posn, unsigned char val)
{
PORTB &= ~SDP8_LOAD; // enable SPI
spi(posn);
spi(val);
PORTB |= SDP8_LOAD; // latch the data on rising edge
}
David. |
|
|
| |
|
|
|
|
|
Posted: Jun 22, 2010 - 01:02 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
ok fixed those mistakes though i'm still getting the same results.
the code is now
Code:
#include <avr/io.h>
#include <util/delay.h>
#define SDP8_LOAD (1<<PB1) // PORTB.1
#define sdp8_data PORTB
#define sdp8_ctl DDRB
void SPI_MasterInit(void)
{
/* Set MOSI and SCK and B0 (B0 is load pin) output, all others input */
DDRB = (1<<DDB5)|(1<<DDB7)|SDP8_LOAD;
/* Enable SPI, Master, set clock rate fck/16 */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
void spi(unsigned char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
;
}
void sdp8(unsigned char posn, unsigned char val)
{
PORTB &= ~SDP8_LOAD; // enable SPI
spi(posn);
spi(val);
PORTB |= SDP8_LOAD; // latch the data on rising edge
}
void initsdp8(void)
{
sdp8(0x0A, 0x07); /* high intensity */
sdp8(0x0B, 0x07); /* scan limit set to digit 0 only, 0x07 for all digits*/
sdp8(0x09, 0xFF); /* no decode (FF for decode all digits)*/
sdp8(0x0C, 0x01); /* not shutdown */
//sdp8(0x0F, 0x01); /* start test*/
//_delay_ms(2000);
sdp8(0x0F, 0x00); /* stop test*/
}
int main(void)
{
initsdp8();
sdp8(0x01, 0x06);
}
i know the problem is neither of the chips as they are brand new.
are there any other problems?
Thanks |
|
|
| |
|
|
|
|
|
Posted: Jun 22, 2010 - 01:17 AM |
|

Joined: Apr 18, 2010
Posts: 43
Location: Wollongong, Australia
|
|
i have just realised that the code doesn't initialise the SPI so i have changed the main function to
Code:
int main(void)
{
SPI_MasterInit();
initsdp8();
sdp8(0x01, 0x06);
}
and now i get nothing no output to the seven segment intermittent or otherwise  |
|
|
| |
|
|
|
|
|