Interfacing MAX7219 with 328p [Solved]

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

trying to interface max 7219 with 328p (both on and off arduino board)

tried both hardware and software spi, both codes works in simulation(proteus) but not in the real world.

here is my code for hardware spi:

#define LOAD_CLEAR    PORTB &= ~(1 << PB2)
#define LOAD_SET PORTB |= (1 << PB2)

void initSPI(void)
{
  DDRB |= (1 << PORTB2);      // Set SS output
  PORTB |= (1 << PORTB2);      // Begin high (unselected)
  DDRB |= (1 << PORTB3);       // Output on MOSI
  DDRB |= (1 << PORTB5);       // Output on SCK
  SPCR |= (1 << MSTR);      // Clock master
  SPCR |= (1 << SPE);       // Enable SPI
  SPCR |= (1 << SPR0);      //fosc/16
}

// Send byte through SPI
void writeByte(uint8_t byte)
{
  SPDR = byte;                      // SPI starts sending immediately
  while(!(SPSR & (1 << SPIF)));     // Loop until complete bit set
}

// Sends word through SPI
void writeWord(uint8_t address, uint8_t data)
{
  LOAD_CLEAR;
  delayMicroseconds(1);
  writeByte(address); // Write first byte
  writeByte(data);      // Write Second byte
  LOAD_SET;
}

void maxInit(void)
{
  initSPI();
  //decode mode
  // 0xff: font b for 0-9 digits
  writeWord(0x09,0xff);
  //Set brightness
  writeWord(0x0A,0x07);
  //set display refresh
  //0x06: only enabling 7 digits
  writeWord(0x0B,0x06);
  //turn on display
  writeWord(0x0C,0x01);
  //disable display test
  writeWord(0x0F,0x00);
}

void rpmDisplay(int value)
{
  uint8_t first = 0, second = 0, third = 0, fourth = 0;

  fourth = value / 1000;
  third = (value % 1000) / 100;
  second = (value % 100) /10;
  first = (value % 10);

  writeWord(0x01, first);
  writeWord(0x02, second);
  writeWord(0x03, third);
  writeWord(0x04, fourth);
}

void speedDisplay(int value)
{
  uint8_t first = 0, second = 0, third = 0;

  third = (value / 100);
  second = (value % 100) /10;
  first = (value % 10);

  writeWord(0x05, first);
  writeWord(0x06, second);
  writeWord(0x07, third);
}

void setup()
{
  delay(100);
  maxInit();
  delay(100);
  //rpmDisplay(100);
  writeWord(0x01, 1);

}

void loop()
{

}

and here is my code for software spi:

#define NOP __asm__ __volatile__ ("nop\n\t")

/* INITIALISATION */
uint8_t LOAD = 10; // set slave select 1 pin
uint8_t CLK = 13; // set clock pin
uint8_t DIN = 11; // set master out, slave in pin
uint8_t lastBit = 0;
byte work = B00000000; // setup a working byte, used to bit shift the data out

void spi_transfer(byte working)
{ // function to actually bit shift the data byte out
  for (int i = 1; i <= 8; i++)
  { // setup a loop of 8 iterations, one for each bit
    lastBit++;
    if (working > 127)  // test the most significant bit
      PORTB |= (1 << PORTB3); // if it is a 1 (ie. B1XXXXXXX), set the master out pin high
    else
      PORTB &= ~(1 << PORTB3); // if it is not 1 (ie. B0XXXXXXX), set the master out pin low

    PORTB |= (1 << PORTB5); // set clock high, the pot IC will read the bit into its register
    working = working << 1;
    if (lastBit == 16)
    {
      lastBit = 0;
      PORTB |= (1 << PORTB2);
    }
    PORTB &= ~(1 << PORTB5); // set clock low
  }
}

void spi_out(byte reg, byte value)
{ // SPI tranfer out function begins here
  PORTB &= ~(1 << PORTB2); // set slave select low for a certain chip, defined in the argument in the main loop. selects the chip
  work = reg; // let the work byte equal the cmd_byte, defined in the argument in the main loop
  spi_transfer(work); // transfer the work byte, which is equal to the cmd_byte, out using spi
  work = value; // let the work byte equal the data for the pot
  spi_transfer(work); // transfer the work byte, which is equal to the data for the pot
  PORTB |= (1 << PORTB2); // set slave select high for a certain chip, defined in the argument in the main loop. deselcts the chip
}

void spiInit()
{
  DDRB |= (1 << PORTB2);      // Set LOAD output
  PORTB |= (1 << PORTB2);      // Begin high (unselected)
  DDRB |= (1 << PORTB3);       // Output on DIN
  DDRB |= (1 << PORTB5);       // Output on ClK
}

void maxInit()
{
  spi_out(0x09, 0xff);
  NOP;
  spi_out(0x0A, 0x07);
  NOP;
  spi_out(0x0B, 0x06);
  NOP;
  spi_out(0x0C, 0x01);
  NOP;
  spi_out(0x0F, 0x00);
  NOP;
}

/* SETUP */
void setup()
{ // setup function begins here
  spiInit();
  maxInit();
  NOP;
  spi_out(0x01, 1);
}

void loop ()
{
}

after lots of trials, I suspected that the malfunction is from the max7219 or the board itself, but I found one piece of code that works :@

//We always have to include the library
#include "LedControl.h"

/*
 Now we need a LedControl to work with.
 ***** These pin numbers will probably not work with your hardware *****
 pin 12 is connected to the DataIn
 pin 11 is connected to the CLK
 pin 10 is connected to LOAD
 ***** Please set the number of devices you have *****
 But the maximum default of 8 MAX72XX wil also work.
 */
LedControl lc=LedControl(11,13,10,8);

/* we always wait a bit between updates of the display */
unsigned long delaytime=50;

/*
 This time we have more than one device.
 But all of them have to be initialized
 individually.
 */
void setup() {
  //we have already set the number of devices when we created the LedControl
  int devices=lc.getDeviceCount();
  //we have to init all devices in a loop
  for(int address=0;address<devices;address++) {
    /*The MAX72XX is in power-saving mode on startup*/
    lc.shutdown(address,false);
    /* Set the brightness to a medium values */
    lc.setIntensity(address,8);
    /* and clear the display */
    lc.clearDisplay(address);
  }
}

void loop() {
  //read the number cascaded devices
  int devices=lc.getDeviceCount();

  //we have to init all devices in a loop
  for(int row=0;row<8;row++) {
    for(int col=0;col<8;col++) {
      for(int address=0;address<devices;address++) {
        delay(delaytime);
        lc.setLed(address,row,col,true);
        delay(delaytime);
        lc.setLed(address,row,col,false);
      }
    }
  }

compiler is arduino and I don't have an oscilloscope at my disposal.

Any advice on what might be the problem is highly appreciated.

This topic has a solution.
Last Edited: Thu. Sep 13, 2018 - 02:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SPI has 4 modes of operation, which of these modes does your real hardware expect? 

Most simulators will default to the mode 0, so does the 328, so it works in simulation but not on the real thing....

 

Read the datasheet SPI section for more info, then check the DS of the device to see if they are the same.

 

Jim

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

Last Edited: Tue. Sep 11, 2018 - 12:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

max7219 works with spi mode 1, and I don't think the spi mode is the issue because if it was the issue, then the software Spi should have worked.

 

Anyway just to be sure, tried 4 trials with the 4 modes and the results were: two modes out of four worked on simulation and none of the trials worked in real world!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rubbish. The MAX7219 is "like" a 74HC595 shift register. It can be driven in SPI mode#0. The LOAD pin is /CS.
.
Your experiments will be much easier if you just use regular SPI class methods in Arduino e.g. select different modes and frequencies.
.
If you want to write your own hardware SPI in the Arduino environment, always use = when assigning to Special Function Registers e.g. SPCR. If you really want to use |= you should use =0 first. Personally, I find the |= style risky and cumbersome.
.
Having made your experiments with Arduino, you can write your own hardware and software functions. And COMPARE their behaviour with your known SPI results.
.
An excellent project for Proteus and for real life.
I do not have a Proteus licence but I would assume that it Simulates a MAX7219 accurately.
.
David,

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As I said a lot of times before, a Logic Analyser is a wonderfull piece of equipment to observe bit patterns on multiple I/O pins.

And because they can be bought for around EUR 5 nowadays, no beginner in uC programmer should go without them.

Search Ali / Ebay / China for "24Mhz 8ch" and use it with the open source Sigrok package.

 

Some time ago I made a few screenshots of how I use it to debug software. The link is:

https://www.avrfreaks.net/forum/led-indicator-software-debugging?skey=led%20debugging

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I used the MAX7219 and aMega88 a few years back for a retro wall clock using discrete LEDs.  THe setup was pretty easy and worked really well.  The SPI files allow you to do bit bang, or use the hardware engine depending on your needs.

 

I have attached the .c and .h files I used.  Just change what you need accordingly and you should be good to go

 

JIm

Attachment(s): 

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?  - Lee "theusch"

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I also have some max7219 stuff around, the initialization code is pretty much identical to yours, I don't see any problem there:

	ldi	tmp_H, Scan_Limit
	ldi	tmp_L, 7		;set up first command: Scan_Limit = 7
SPI_SEND_16

	ldi	tmp_H, Decode_Mode
	ldi	tmp_L, 0b00000000	;set up 2nd command: Decode_Mode = 0b00011111
SPI_SEND_16

	ldi	tmp_H, Intensity
	ldi	tmp_L, 4		;set up 3rd command: Intensity = 4
SPI_SEND_16

	ldi	tmp_H, Test
	ldi	tmp_L, 0		;set up 4th command: Test mode = OFF
SPI_SEND_16

	ldi	tmp_H, Shutdown
	ldi	tmp_L, 1		;set up 5th command: leave Shutdown mode = YES
SPI_SEND_16

The only problem I had, was buying fake or defective chips from China that failed after just a few months...

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for everyone tried to help.

After some code and physical segment behavior in depth inspection, a 0.1uf ceramic cap between Vcc & Gnd of the chip solved the problem.

 

The problem was in hardware not in software, and all the posted codes up are working fine!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please mark your last post as the solution then

Jim

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?  - Lee "theusch"

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user