Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
baker158
PostPosted: Apr 18, 2010 - 05:07 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
ka7ehk
PostPosted: Apr 18, 2010 - 05:32 AM
10k+ Postman


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
 
 View user's profile Send private message  
Reply with quote Back to top
baker158
PostPosted: Apr 18, 2010 - 06:00 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
ka7ehk
PostPosted: Apr 18, 2010 - 07:31 AM
10k+ Postman


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
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Apr 18, 2010 - 10:58 AM
10k+ Postman


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.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
baker158
PostPosted: Apr 19, 2010 - 01:58 AM
Rookie


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?
 
 View user's profile Send private message  
Reply with quote Back to top
ka7ehk
PostPosted: Apr 19, 2010 - 02:08 AM
10k+ Postman


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
 
 View user's profile Send private message  
Reply with quote Back to top
baker158
PostPosted: Apr 20, 2010 - 02:21 AM
Rookie


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)))
{;}
}
 
 View user's profile Send private message  
Reply with quote Back to top
js
PostPosted: Apr 20, 2010 - 04:40 AM
10k+ Postman


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
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
Jepael
PostPosted: Apr 20, 2010 - 05:39 AM
Raving lunatic


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.
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Apr 20, 2010 - 09:29 AM
10k+ Postman


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.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
baker158
PostPosted: May 14, 2010 - 07:28 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: May 14, 2010 - 08:25 AM
10k+ Postman


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.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
baker158
PostPosted: May 15, 2010 - 12:04 AM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: May 15, 2010 - 08:04 AM
10k+ Postman


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.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
baker158
PostPosted: May 16, 2010 - 05:59 AM
Rookie


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 Embarassed

thanks for the help
 
 View user's profile Send private message  
Reply with quote Back to top
baker158
PostPosted: Jun 21, 2010 - 10:41 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jun 21, 2010 - 10:57 AM
10k+ Postman


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.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
baker158
PostPosted: Jun 22, 2010 - 01:02 AM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
baker158
PostPosted: Jun 22, 2010 - 01:17 AM
Rookie


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 Sad
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits