3

im trying to use my Micro OLED Sparkfun display (here is the datasheet enter link description here) but i have a problem about code. Maybe is the problem in code because im working first time with SPI in Atmel so if would be somebody so nice and check it out, give me some advices about i will be so thankful.

EDIT: Here is the changed code and picture of display wires

#define F_CPU 16000000
 #include <avr/io.h>
 #include <util/delay.h>
 #define SCK DDB5
 #define SDIN DDB3
 #define D_C DDB0
 #define CS DDB2
 #define RST DDB1

 void SPI_MasterInit(void)
 {
     /* Set MOSI and SCK output, all others input */
     DDRB = (1<<SCK)|(1<<SDIN)|(1<<D_C)|(1<<CS)|(1<<RST);
     /* Enable SPI, Master, set clock rate fck/16 */
     PORTB |= (1<<CS);
     PORTB |= (1<<D_C);
     SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(0<<DORD);
 }
 void SPI_MasterTransmit_Command(int cCommand)
 {
     PORTB &= ~(1<<CS);
     PORTB &= ~(1<<D_C);
     _delay_ms(200);
     /* Start transmission */
     SPDR = cCommand;
     /* set dc and cs low to send command */
     /* Wait for transmission complete */
     while(!(SPSR & (1<<SPIF)));
     /* set dc cs high again */
     PORTB |= (1<<CS);
     PORTB |= (1<<D_C);


 }

 void Display_ON(void)
 {
     PORTB &= ~(1<<RST);
     _delay_ms(50);
     PORTB |= (1<<RST);
     _delay_ms(50);
     PORTB &= ~(1<<RST);
     _delay_ms(50);
     SPI_MasterTransmit_Command(0xAF);
     _delay_ms(200);
 }

 int main(void)
 {
     SPI_MasterInit();
     Display_ON();
     SPI_MasterTransmit_Command(0xA5);

 }

enter image description here

Rev
  • 5,827
  • 4
  • 27
  • 51
  • How the display controller is connected to the board? What is PB0 ? PB1 ? Where CS# is connected and where it is controlled? There is no in your code where you pull something down before the comand and pull it up just after. – AterLux Sep 23 '18 at 11:58
  • I recommend you change C/D before asserting chip select. Dont think that is your problem but you dont want a race there. – old_timer Sep 24 '18 at 16:52
  • If you are using a spi perpiheral in a chip it is best to have a scope. They are much cheaper now for about $250 you can get a 4 channel that will work nicely for this application. if not get some leds put them on the outputs of the mcu, try to clock the mcu as slow as possible and see if you can visually see the states changing on the leds. If not get another mcu and use it to poll the lines, turn it into a logic analyzer. Assume the chip vendor docs are buggy, even if only one bug in the docs it could be in the peripheral you are working on... – old_timer Sep 24 '18 at 16:55
  • Ignore the "mode" numbers look at the datasheet for the slave, on the scope or logic analyzer make sure the data changes state on the correct half clock edge so that the slave will sample it on the correct clock edge. Likewise in reverse although with displays like this you often dont need to read anything back. – old_timer Sep 24 '18 at 16:56
  • remove the second PORTB &= ~(1< – AterLux Sep 25 '18 at 07:13

2 Answers2

1

First. When you're using SPI on AVR ATmega in the master mode, the SS pin, although it is not used directly by the SPI module, should be always configured as output, otherwise, high level on the pin will switch the SPI module into the slave mode. In other words, if you're using, for example, ATmega328(P), the PB2 should be configured as output (DD2 bit in DDRB should be set). It is a good idea to connect CS# of SSD1306 to this pin.

Second. When connecting SSD1306 there are 4 lines should be connected (see page 17 of the datasheet): 1) SCLK - serial clock - connect it to the SCK pin of the SPI port (e.g. PB5 for ATmega328) 2) SDAT - serial data - connect it to the MOSI pin (PB3) 3) CS# - chip select - connect it to the SS pin (PB2) 4) D/#C - data/command select - connect it to any free pin (as I suppose you have connected it to PB0) Also the modules may have RESET input, I think you have it connected to the PB1.

So, sending a data or command byte to the SSD1306 should look like this:

PORTB &= ~(1 << CS); // pulling the CS# line low
PORTB |= (1 << D_C); // high for DATA
or
PORTB &= ~(1 << D_C); // low for COMMAND
SPDR = cData; // transmit the byte
while(!(SPSR & (1<<SPIF))) {} // wait the transmission to complete
PORTB |= (1 << CS); // pull the CS# line back high

CS# can be held low through several commands, without rising up. It helps to determine edges of the command.

Third. Command 0xAF will turn the display on but probably it will show nothing because there is no data in it, so you may see no difference. Try to send command 0xA5 just after that, it will light up all the pixels - just for the test purposes.

UPD Also, there you have to turn on the DC-DC charge pump (see the application note, page 62 at the end of the datasheet). It is done by a sequence of two command bytes 0x8D 0x14. Send it before the turining the display on (i.e. before 0xAF)

AterLux
  • 4,566
  • 2
  • 10
  • 13
0

Unfortunately, you didn't specify the exact µC you are using. I just used the ATMEGA32 as a reference. Hopefully, your AVR has the same configuration.

ATMEGA32 also has an SPI interface on Port B. You rely on the reset value of the DDRB-Register (which is zero). It would be nice to explicitly set all the desired values for your pin configuration. From the ATMEGA's datasheet it seems that you did not initialize the pins correctly. Only PB7 and PB5 of the SPI interface need to be set to output. In your intialization you set PB4, PB6 and PB7 to output. You mixed MISO and MOSI.

Here my initialization routine:

/* 
SPI pin configuration:
PB7: SCK         Output
PB6: MISO        Input
PB5: MOSI        Output
PB4: Chip select Output
*/
void SPI_MasterInit(void){
  DDRB = 0x00;
  DDRB |= ((1 << DDB2) | (1 << DDB5) | (1 << DDB7));
  PORTB |= (1<<PB2);
  /* Enable SPI, Master, set clock rate fck/16 */
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}

You also need to check the following:

  • Does the display support your chosen SPI frequency?
  • What should the state of SCK be during IDLE?
  • When should SPI data be sampled? During the rising or the falling edge of SCK.
  • Is the CS set according to the timing diagram in the OLED display's data sheet?

If you took care of all those things, please come back with a short feedback. I hope this answer gives you some guidelines how to proceed.

Matthias
  • 71
  • 5
  • Hi, im using atmega328p, i did small upgrades in the code, but suddenly display still doesnt want to work https://pastebin.com/zG3JpwWv –  Sep 22 '18 at 15:54
  • In your new code you set `SDIN` as output (which should be an input) and you pull `CS`down after your initialization, which you shouldn't do. A low on CS activates the SPI interface of the display. You should only set it to low if you want to start the communication, e.g. when you start transmitting data. Only configure it as an output. – Matthias Sep 22 '18 at 16:18