T
T
termo3002018-03-28 13:47:44
Microcontrollers
termo300, 2018-03-28 13:47:44

How not to lose connection between ATmega16A and LCD Nokia5110 via SPI?

The crux of the problem is this. I decided to master SPI and communication with the Nokia 5110 display. I encountered a loss of communication at random times - the display receives data from 1 to 10 seconds, after which the controller waits an infinitely long time for a response about data transfer.
For programming, I use ATmega16A-PU with an internal 8MHz frequency generator, USBASP v2.0 in-circuit programmer, Atmel Studio 7, and AVRDUDE.
More or less stable operation of the program is possible when setting F_CPU=1000UL and frequency divider SPI f/128. In addition, more stable operation of the device is observed when the programmer connector is connected - the display showed a counter from 10 seconds to a couple of minutes.
With a normal F_CPU, communication with the display ends after the second display setup command. After that, the controller sends one command every 2-10 minutes, but in the end there is still no image on the display.
I read about the need for external quartz, installed it according to the datasheet, connecting my legs to the ground through film capacitors (50V 15pF). The microcontroller was flashed and worked for a total of 15 minutes, after which it never answered the programmer's requests and did not execute the program. What can be done wrong here?
Tell me, please, what could be the reason for this behavior (low F_CPU values, greater stability when a programmer is connected, delayed death when a quartz is connected)? Installed another copy of the microcontroller, everything is the same.

Wiring diagram:
5abb68b82017f101544229.png
Program code
--Introduction
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>

unsigned char ii;
unsigned char s,m,h;
int s2,s3,h2,h3,m2,m3;
--Timer settings for display
void timer_ini(void)
{
  TCCR1B |= (1<<WGM12); // устанавливаем режим СТС (сброс по совпадению)
  TIMSK |= (1<<OCIE1A); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)
  OCR1AH = 0b00111101; //записываем в регистр число для сравнения
  OCR1AL = 0b00001001;
  TCCR1B |= (1<<CS11)|(1<<CS10);//установим делитель f/128.
}
--Blinking status LED
void mig(int dl)
{
  PORTD |= (1<<PORTD7); 
  //моргаем светодиодиком в знак выполнения команд
  for(ii=0;ii<=(dl/100);ii++)
  {
    _delay_ms(100);
  }
  PORTD &= ~(1<<PORTD7);
  for(ii=0;ii<=(dl/100);ii++)
  {
    _delay_ms(100);
  }
}
--Передача по SPI
void senddata(unsigned char snd)
{
  SPDR = snd;
  while(!(SPSR & (1<<SPIF))){
    PORTD |=(1<<PORTD6);//подождем пока данные передадутся и пока посветим диодиком
  }
  PORTD &= ~(1<<PORTD6);
}
--Подача настроечных команд на дисплей
void initscr(void)
{
  PORTD &= ~((1<<PORTD0)|(1<<PORTD1)|(1<<PORTD2)); //ножки RST, CE(SS), D/C низкий уровень
  _delay_ms(1);
  //PORTD |= ((1<<PORTD1)|(1<<PORTD2));//сброс SS и RST
  PORTD |= (1<<PORTD0);//сброс RST
  senddata(0b00100001);// отправка настроечных команд
  senddata(0b00010011);
  senddata(0b00000100);
  senddata(0b11000001);
  senddata(0b00100000);
  senddata(0b00001100);

  PORTD |=(1<<PORTD2); // включим передачу рисовашек
  PORTD |= (1<<PORTD1);//сброс SS
}
--Процедура отрисовки символов
void sendchar(unsigned char str)
{
  // в зависимости от символа рисуем его заранее подобранными командами.
  switch (str)
  {
    case ('A') : senddata(0xF8);senddata(0x24);senddata(0x22);senddata(0x24);senddata(0xF8);senddata(0x00); break;
    // и так далее каждый символ
  }
}
--Вывод на экран строки
void sendstr(char str1[])
{
  unsigned int n;
  // посылаем на экран строки, разбивая их посимвольно
  PORTD &= ~(1<<PORTD1); //ножка CE(SS) низкий уровень
  for(n=0;str1[n]!='\0';n++)
  {
    sendchar(str1[n]);
  }
  PORTD |= (1<<PORTD1);//сброс SS
}
--Очистка экрана
void clearscr(void)
{
  unsigned int n;
  // очитсим экран, послав пробел много раз
  PORTD &= ~(1<<PORTD1); //ножка CE(SS) низкий уровень
  for(n=0;n<=83;n++){
    sendchar(' ');
  }
  PORTD |= (1<<PORTD1);//сброс SS
}
--Настройка SPI
void initSPI(void)
{
  DDRB |= ((1<<PORTB5)|(1<<PORTB7)); //ножки SPI (MOSI и SCK) на выход
  PORTB |= ((1<<PORTB5)|(1<<PORTB7)); //низкий уровень
  DDRB &= ~(1<<PORTB6);// ножка MISO на вход
  SPCR |= ((1<<SPE)|(1<<MSTR));	//Включим шину, объявим ведущим
  SPCR |= ((1<<SPR0)|(1<<SPR1));//установим делитель f/128.
  SPSR &= ~(1<<SPR0);
  
  DDRD |= 0xFF; // ножки на выход
  PORTD &= ~(1<<PORTD7);//выключим диод
}
--Счетчик по прерыванию
ISR (TIMER1_COMPA_vect)
{ //запустим счетчики часов, минут и секунд
    s++;
    if (s==60)
    {
      m++;
      s=0;
      if(m==60)
      {
        h++;
        m=0;
      }
    }
    // отделим десятки и единицы часов, минут и секунд друг от друга
    h2=h/10;
    h3=h%10;
                
    m2=m/10;
    m3=m%10;
                
    s2=s/10;
    s3=s%10;
}
--Главная
int main(void)
{
  timer_ini();
  initSPI();
  mig(1000); //после выполнения процедуры инициализации таймера и SPI моргнем на секунду
  
  initscr();
  mig(300);//после выполнения процедуры инициализации дисплея моргнем быстро три раза
  mig(300);
  mig(300);
  
  clearscr();
  mig(300); // очистим экран и моргнем быстро три раза
  mig(300);
  mig(300);
  
  // поприветствуем кого-нибудь
  sendstr("              ");
  sendstr("     Всем     ");
  sendstr("    привет!   ");
  sendstr("              ");
  sendstr("   -=(o_O)=-  ");
  sendstr("              ");
  _delay_ms(3000);
  sei(); // запустим счетчик
  while(1)
  {
    // и каждые полсекунды посылаем на экран текущее время отсчета
    sendstr("              ");
    sendstr("              ");
    sendstr("   ");
    switch (h2)
    {
      case 0: sendstr("0");break;
      case 1: sendstr("1");break;
      case 2: sendstr("2");break;
      case 3: sendstr("3");break;
      case 4: sendstr("4");break;
      case 5: sendstr("5");break;
      case 6: sendstr("6");break;
      case 7: sendstr("7");break;
      case 8: sendstr("8");break;
      case 9: sendstr("9");break;
    }
    switch (h3)
    {
      case 0: sendstr("0");break;
      case 1: sendstr("1");break;
      case 2: sendstr("2");break;
      case 3: sendstr("3");break;
      case 4: sendstr("4");break;
      case 5: sendstr("5");break;
      case 6: sendstr("6");break;
      case 7: sendstr("7");break;
      case 8: sendstr("8");break;
      case 9: sendstr("9");break;
    }
    sendstr(":");
    switch (m2)
    {
      case 0: sendstr("0");break;
      case 1: sendstr("1");break;
      case 2: sendstr("2");break;
      case 3: sendstr("3");break;
      case 4: sendstr("4");break;
      case 5: sendstr("5");break;
      case 6: sendstr("6");break;
      case 7: sendstr("7");break;
      case 8: sendstr("8");break;
      case 9: sendstr("9");break;
    }
    switch (m3)
    {
      case 0: sendstr("0");break;
      case 1: sendstr("1");break;
      case 2: sendstr("2");break;
      case 3: sendstr("3");break;
      case 4: sendstr("4");break;
      case 5: sendstr("5");break;
      case 6: sendstr("6");break;
      case 7: sendstr("7");break;
      case 8: sendstr("8");break;
      case 9: sendstr("9");break;
    }
    sendstr(":");
    switch (s2)
    {
      case 0: sendstr("0");break;
      case 1: sendstr("1");break;
      case 2: sendstr("2");break;
      case 3: sendstr("3");break;
      case 4: sendstr("4");break;
      case 5: sendstr("5");break;
      case 6: sendstr("6");break;
      case 7: sendstr("7");break;
      case 8: sendstr("8");break;
      case 9: sendstr("9");break;
    }
    switch (s3)
    {
      case 0: sendstr("0");break;
      case 1: sendstr("1");break;
      case 2: sendstr("2");break;
      case 3: sendstr("3");break;
      case 4: sendstr("4");break;
      case 5: sendstr("5");break;
      case 6: sendstr("6");break;
      case 7: sendstr("7");break;
      case 8: sendstr("8");break;
      case 9: sendstr("9");break;
    }
    sendstr("   ");
    sendstr("              ");
    sendstr("              ");
    sendstr("              ");
    _delay_ms(500);
  }
}

Answer the question

In order to leave comments, you need to log in

2 answer(s)
V
vanyamba-electronics, 2018-03-28
@termo300

Try 10-20K pull-up resistors.

T
termo300, 2018-03-31
@termo300

So, the solution was to use the SS leg (in my case it is PB4) in the code, explicitly specifying it as an output.
Since I used a completely different leg (PD7) to select a controlled device, I decided not to define the regular one in the code at all. Connecting a pull-up resistor to it made it immune to random signals.
The documentation says that when you turn on the master mode via SPI, the signal coming to this leg automatically turns off the master, as it means that another master has selected this device as a slave. And by default, the leg is the input, and random pickups gave such a result.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question