Синтезатор (VFO) ad9850 и ILI9341 2.2

varvik85
Offline
Зарегистрирован: 28.01.2013

Здравствуйте.Появилась потребность в синтезаторе для трансивера.Взял готовый пример http://www.ad7c.com/projects/ad9850-dds-vfo/ и решил адаптировать его под цветной tft дисплей.Возникла трудность,при вращении н-кодера цифры на дисплее не обнавляются,а как бы пишутся поверх старых,т е был 0 а сверху написаллас 1 2 3 4 и в итоге каша. Подскажите что нужно добавить в коде?Может нужно сбрасывать постоянно при обновлении переменной,но как?


#include <rotary.h>
#include <EEPROM.h>
//Setup some items
#define W_CLK 4   // Pin 8 - connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 5   // Pin 9 - connect to freq update pin (FQ)
#define DATA 6   // Pin 10 - connect to serial data load pin (DATA)
#define RESET 7  // Pin 11 - connect to reset pin (RST) 
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
Rotary r = Rotary(2,3); // sets the pins the rotary encoder uses.  Must be interrupt pins.
int_fast32_t rx=7200000; // Starting frequency of VFO
int_fast32_t rx2=1; // variable to hold the updated frequency
int_fast32_t increment = 10; // starting VFO update increment in HZ.
int buttonstate = 0;
String hertz = "10 Hz";
int  hertzPosition = 5;
byte ones,tens,hundreds,thousands,tenthousands,hundredthousands,millions ;  //Placeholders
String freq; // string to hold the frequency
int_fast32_t timepassed = millis(); // int to hold the arduino miilis since startup
int memstatus = 1;  // value to notify if memory is current or old. 0=old, 1=current.





int ForceFreq = 1;  // Change this to 0 after you upload and run a working sketch to activate the EEPROM memory.  YOU MUST PUT THIS BACK TO 0 AND UPLOAD THE SKETCH AGAIN AFTER STARTING FREQUENCY IS SET!


#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#define TFT_DC 9
#define TFT_CS 10
#define TFT_MOSI 11
#define TFT_CLK 13
#define TFT_RST 8
#define TFT_MISO 12
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

void setup() {
 
 
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);


pinMode(A0,INPUT); // Connect to a button that goes to GND on push
  digitalWrite(A0,HIGH);
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();
  pinMode(FQ_UD, OUTPUT);
  pinMode(W_CLK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(RESET, OUTPUT); 
  pulseHigh(RESET);
  pulseHigh(W_CLK);
  pulseHigh(FQ_UD);  // this pulse enables serial mode on the AD9850 - Datasheet page 12.   
   // Load the stored frequency  
  if (ForceFreq == 0) {
    freq = String(EEPROM.read(0))+String(EEPROM.read(1))+String(EEPROM.read(2))+String(EEPROM.read(3))+String(EEPROM.read(4))+String(EEPROM.read(5))+String(EEPROM.read(6));
    rx = freq.toInt();  


}
  

}



void loop() {
  if (rx != rx2){    
        showFreq();
        sendFrequency(rx);
        rx2 = rx;
      }
      
  buttonstate = digitalRead(A0);
  if(buttonstate == LOW) {
        setincrement();        
    };

  // Write the frequency to memory if not stored and 2 seconds have passed since the last frequency change.
    if(memstatus == 0){   
      if(timepassed+2000 < millis()){
        storeMEM();
        }
      }   
}


ISR(PCINT2_vect) {
  unsigned char result = r.process();
  if (result) {    
    if (result == DIR_CW){rx=rx+increment;}
    else {rx=rx-increment;};       
      if (rx >=30000000){rx=rx2;}; // UPPER VFO LIMIT
      if (rx <=1000000){rx=rx2;}; // LOWER VFO LIMIT
  }
}



// frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {  
  int32_t freq = frequency * 4294967295/125000000;  // note 125 MHz clock on 9850.  You can make 'slight' tuning variations here by adjusting the clock frequency.
  for (int b=0; b<4; b++, freq>>=8) {
    tfr_byte(freq & 0xFF);
  }
  tfr_byte(0x000);   // Final control byte, all 0 for 9850 chip
  pulseHigh(FQ_UD);  // Done!  Should see output
}
// transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data)
{
  for (int i=0; i<8; i++, data>>=1) {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //after each bit sent, CLK is pulsed high
  }
}

void setincrement(){
  if(increment == 10){increment = 50; hertz = "50 Hz"; hertzPosition=5;}
  else if (increment == 50){increment = 100;  hertz = "100 Hz"; hertzPosition=4;}
  else if (increment == 100){increment = 500; hertz="500 Hz"; hertzPosition=4;}
  else if (increment == 500){increment = 1000; hertz="1 Khz"; hertzPosition=6;}
  else if (increment == 1000){increment = 2500; hertz="2.5 Khz"; hertzPosition=4;}
  else if (increment == 2500){increment = 5000; hertz="5 Khz"; hertzPosition=6;}
  else if (increment == 5000){increment = 10000; hertz="10 Khz"; hertzPosition=5;}
  else if (increment == 10000){increment = 100000; hertz="100 Khz"; hertzPosition=4;}
  else if (increment == 100000){increment = 1000000; hertz="1 Mhz"; hertzPosition=6;}  
  else{increment = 10; hertz = "10 Hz"; hertzPosition=5;};  
   //lcd.setCursor(0,1); ****************************************************************************************************************************
   //lcd.print("                ");
   //lcd.setCursor(hertzPosition,1); 
   //lcd.print(hertz); 

 tft.setTextColor(ILI9341_GREEN);
   tft.setTextSize(3);
   tft.setCursor(0,1);
   tft.print("                ");
   tft.setCursor(hertzPosition,1); 
   tft.print(hertz); 
   
   
   delay(250); // Adjust this delay to speed up/slow down the button menu scroll speed.
};

void showFreq(){
    millions = int(rx/1000000);
    hundredthousands = ((rx/100000)%10);
    tenthousands = ((rx/10000)%10);
    thousands = ((rx/1000)%10);
    hundreds = ((rx/100)%10);
    tens = ((rx/10)%10);
    ones = ((rx/1)%10);
   // lcd.setCursor(0,0);*******************************************************************************************************************************
   // lcd.print("                ");
   tft.setTextColor(ILI9341_GREEN);
   tft.setTextSize(3);
   if (millions > 9){tft.setCursor(0, 0);}
   else{tft.setCursor(0, 6);}
    tft.print(millions);
    tft.print(".");
    tft.print(hundredthousands);
    tft.print(tenthousands);
    tft.print(thousands);
    tft.print(".");
    tft.print(hundreds);
    tft.print(tens);
   tft.print(ones);
    tft.print(" Mhz  ");
    timepassed = millis();
    memstatus = 0; // Trigger memory write
     
};

void storeMEM(){
  //Write each frequency section to a EPROM slot.  Yes, it's cheating but it works!
   EEPROM.write(0,millions);
   EEPROM.write(1,hundredthousands);
   EEPROM.write(2,tenthousands);
   EEPROM.write(3,thousands);
   EEPROM.write(4,hundreds);       
   EEPROM.write(5,tens);
   EEPROM.write(6,ones);   
   memstatus = 1;  // Let program know memory has been written
};

 

MagicianT
Offline
Зарегистрирован: 03.10.2015

Закрасьте чёрным квадратиком поле вывода цифр, перед тем как печатать. Можно и весь экран закрасить, по усмотрению.

  tft.fillRect( 0, BOXSIZE, tft.width(), tft.height(), BLACK);

 

varvik85
Offline
Зарегистрирован: 28.01.2013

Здравствуйте!Спасибо.Я Использовал следующие строчки в начале print на дисплей

 tft.fillRect(0, 0, 200, 40, ILI9341_BLACK);

Но,обновляется очень медленно,я поворачиваю н-кодер и и после этого,где то секунду обновляется квадратик,сверху вниз закрашивается черным.Что еще можно предпринять?Пологаю если закрашивать весь экран,то будет еще медленее.Нет каких то более быстрых "очисток" дисплея?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ну, библиотека у Вас под руками, кому, как не Вам, смотреть, какие там есть функции.

Судя вот по этому:

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

интерфейс последовательный, протокол софтверный. Давайте посчитаем:

Вы выводите 200*40=8000 пикселей по два байта каждый. Это примерно 128 кбит. Если все это укладывается в секунду, то для указанных ограничений совсем не плохо.

Если аппаратной очистки нет, а скорость обновлекния экрана категорически не устраивает, существуют варианты:

1. Заменить диспдлей на другой - с параллельным интерфейсом. Минус - он займет минмум вдвое больше ног контроллера.

2. Отказаться от цветного дисплея в пользу монохромного (с однибитным цветом).

varvik85
Offline
Зарегистрирован: 28.01.2013

Я видел несколько видео на ютубе,к сожалению без кода,в которых обновление происходит в разы быстрее,вот например https://www.youtube.com/watch?v=rYAn4rj_MSk у меня по сравнению раз в шесть медленнее,не пойму в чем причина

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

varvik85, по вашей ссылке есть код: https://kennethwong.org/projects/electricaudi/instrument-cluster-part-2/

смотреть и комментировать лень :-)

MagicianT
Offline
Зарегистрирован: 03.10.2015

У него библиотека другая, что вас останавливает содрать его код и посмотреть?

https://drive.google.com/file/d/0ByVBIKRZJdkIc2JoVzRjZ01kQkU/edit

 
varvik85
Offline
Зарегистрирован: 28.01.2013

Здравствуйте!Спасибо за помощь и интерес к моей проблеме.Дело в том,что мой дисплей не работает с другими библиотеками кроме Adafruit_ILI9341 пробовал разные TFT TFT2 UTFT UTFT-master с разными вариантами подключений,есть много примеров использования ILI9341 например http://arduino.ru/forum/apparatnye-voprosy/displei-na-ili9341 перепробовал все,не работает,работает только Adafruit_ILI9341  и инициализацией которая у меня в коде.То-же странно почему так,может я где-то косячу,но вроде неоднократно все перепроверял.Так вот, некоторые функции из библиотек TFT TFT2 UTFT UTFT не подходят для Adafruit_ILI9341 например initlcd()   clrscr(); по этому не всегда получается использовать чужой код. Что работает так это  tft.begin(); - инициализация дисплея и tft.fillRect(0, 0, 200, 40, ILI9341_BLACK); - тут я закрашиваю квадрат с цифрами черным,но закрашивается ооочень медлено,можно как то корректнее все это сделать,например не закрашивать квадрат а именно как то сбрасывать дисплей чтоб цифры менялись,но я не знаю какой командой.Может библиотека Adafruit_ILI9341 какая то корявая и по этому у меня так медленно все обновляется,или что то в коде что то тормозит?В любом случае,большое спасибо за советы!

MagicianT
Offline
Зарегистрирован: 03.10.2015

У меня есть смутное подозрение, что скорость будет зависеть от способа инициализации адафрута-либа, там определено 2 конструктора.

// For the Adafruit shield, these are the default.
#define TFT_DC 9
#define TFT_CS 10

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

Так вот, по второму способу, как и у вас, пины - произвольно выбираются, а значит используется бит-бэнг а не хардваре  SPI. Попробуйте другую версию, короткую.

varvik85
Offline
Зарегистрирован: 28.01.2013

Здравствуйте.Спасибо.Но у меня опять ничего не работает.

подключаю дисплей к пинам (как в readme)

D4 :  RESET
D5 :  CS
D6 :  D/C
D7 :  LED
D11 : MOSI
D12 : MISO
D13 : SCK
Не работает

После меняю
DC на 9
CS на 10
Все равно не работает (((

Работает только та инициализация которая у меня в коде,почему?Что я не так подключаю?

MagicianT
Offline
Зарегистрирован: 03.10.2015

Какой у вас дисплей? Фото, линк на веб-страницу и т.д. 

Посмотрите на адафрут классы, там подключение в разных вариантах, 
Цитата:

Wiring

Wiring up the display in SPI mode is much easier than 8-bit mode since there's way fewer wires. Start by connecting the power pins


  • 3-5V Vin connects to the Arduino 5V pin
  • GND connects to Arduino ground
  • CLK connects to SPI clock. On Arduino Uno/Duemilanove/328-based, thats Digital 13. On Mega's, its Digital 52 and on Leonardo/Due its ICSP-3 (See SPI Connections for more details)
  • MISO connects to SPI MISO. On Arduino Uno/Duemilanove/328-based, thats Digital 12. On Mega's, its Digital 50 and on Leonardo/Due its ICSP-1 (See SPI Connections for more details)
  • MOSI connects to SPI MOSI. On Arduino Uno/Duemilanove/328-based, thats Digital 11. On Mega's, its Digital 51 and on Leonardo/Due its ICSP-4 (See SPI Connections for more details)
  • CS connects to our SPI Chip Select pin. We'll be usingDigital 10 but you can later change this to any pin
  • D/C connects to our SPI data/command select pin. We'll be using Digital 9 but you can later change this pin too.

That's it! You do not need to connect the RST or other pins for now.

https://learn.adafruit.com/adafruit-2-dot-8-color-tft-touchscreen-breakout-v2/downloads?view=all#wiring

https://learn.adafruit.com/adafruit-2-dot-8-color-tft-touchscreen-breakout-v2/downloads?view=all#wiring

 

varvik85
Offline
Зарегистрирован: 28.01.2013

Здравствуйте.Спасибо!Дисплей у меня вот такой http://ru.aliexpress.com/item/Smart-Electronics-2-2-Inch-240-320-Dots-SPI-TFT-LCD-Serial-Port-Module-Display-ILI9341/32597442041.html?spm=2114.13010608.0.129.ZVa7Ud

Я подключал по описанию как Вы прислали,тишина....а вот

"That's it! You do not need to connect the RST or other pins for now." интересно,ресет не нужен получается,а почему?

MagicianT
Offline
Зарегистрирован: 03.10.2015

Понятно, китай, они что угодно могут написать в названии. Может оказаться и не ILI9341 а SPFD5408 или ещё какой. У адафрута вроде должна писать тип контроллера при старте, у вас когда он работает там чего писало?

varvik85
Offline
Зарегистрирован: 28.01.2013

Да вродь ничего не писала,это измененная либа

MagicianT
Offline
Зарегистрирован: 03.10.2015

Там ещё бенчмарк есть, не сравивали? 

https://learn.adafruit.com/assets/15445

nik182
Онлайн
Зарегистрирован: 04.05.2015

MagicianT пишет:

Понятно, китай, они что угодно могут написать в названии. Может оказаться и не ILI9341 а SPFD5408 или ещё какой. У адафрута вроде должна писать тип контроллера при старте, у вас когда он работает там чего писало?

Конкретно 9341 не имеет кода опознавания по стандартной процедуре. Если с какой то библиотекой инициализировался - это лучшее доказательство марки дисплея.

Если библиотека смогла нарисовать квадрат на экране, то этого достаточно, для реализации любых других действий. Если библиотека не может что то после этого сделать - это только вопрос кривых ручек. Чужой код легко подпрограммами-обёртками подгоняется к конкретной библиотеке,но это тоже влияет на скорость отрисовки.

Аппаратной очистки нет. Поэтому только программно чистить минимально необходимые квадраты. Скорость по SPI действительно очень маленькая. Только тотальная оптимизация кода и библиотеки даёт приемлемый результат. У меня ili9341 при 16 битной параллельной шине, при аппаратном заполнении через DMA, при тактовой частоте 72МГц заполняет весь экран 0.1 секунды. Множте эту цифру на spi(как минимум 16!) и на разницу в такте - получаются секунды в лучшем случае.   

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

nik182 пишет:

...0.1 секунды. Множте эту цифру на spi(как минимум 16!) и на разницу в такте - получаются секунды в лучшем случае.   

16! = 20922789888000

Так что если верить Вам, то речь может идти не о секундах, а о сотнях тысяч лет.

nik182
Онлайн
Зарегистрирован: 04.05.2015

Восклицательный знак прошу рассматривать как выражение экспрессии сообщения, а не как знак факториала :-)

 

Mining
Offline
Зарегистрирован: 31.01.2016

А нокиа 5110 никто не привинчивал?