1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-23 16:25:16 +03:00

[MEGA2560] Add KS108 lcd + voice + "far" splash for firmware > 64Kb (#3515)

This commit is contained in:
Bertrand Songis 2016-05-25 21:21:51 +02:00
parent 907b6337fc
commit 5f65217124
25 changed files with 1250 additions and 726 deletions

View file

@ -17,3 +17,4 @@ Karl Szmutny
Michal Hlavinka Michal Hlavinka
Pat Mackenzie Pat Mackenzie
Michael Byrne Michael Byrne
Christophe Brision (Ingwie)

View file

@ -1160,6 +1160,7 @@ void addOpenTxLcdOptions(OpenTxFirmware * firmware)
{ "ST7565R", QObject::tr("ST7565R LCD or compatible") }, { "ST7565R", QObject::tr("ST7565R LCD or compatible") },
{ "ERC12864FSF", QObject::tr("ERC12864FSF LCD") }, { "ERC12864FSF", QObject::tr("ERC12864FSF LCD") },
{ "ST7920", QObject::tr("ST7920 LCD") }, { "ST7920", QObject::tr("ST7920 LCD") },
{ "KS108", QObject::tr("KS108 LCD") },
{ NULL } { NULL }
}; };
firmware->addOptions(lcd_options); firmware->addOptions(lcd_options);
@ -1433,7 +1434,7 @@ void registerOpenTxFirmwares()
firmware->addOption("nocurves", QObject::tr("Disable curves menus")); firmware->addOption("nocurves", QObject::tr("Disable curves menus"));
firmware->addOption("sdcard", QObject::tr("Support for SD memory card")); firmware->addOption("sdcard", QObject::tr("Support for SD memory card"));
firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker")); firmware->addOption("audio", QObject::tr("Support for radio modified with regular speaker"));
//firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode")); firmware->addOption("voice", QObject::tr("Used if you have modified your radio with voice mode"));
firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode")); firmware->addOption("haptic", QObject::tr("Used if you have modified your radio with haptic mode"));
firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits")); firmware->addOption("ppmca", QObject::tr("PPM center adjustment in limits"));
firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT); firmware->addOption("gvars", QObject::tr("Global variables"), GVARS_VARIANT);

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -633,7 +633,7 @@ else()
option(BATTGRAPH "Battery graph" OFF) option(BATTGRAPH "Battery graph" OFF)
option(HAPTIC "Haptic support" OFF) option(HAPTIC "Haptic support" OFF)
set(TTS "EN" CACHE STRING "TTS language") set(TTS "EN" CACHE STRING "TTS language")
set(LCD "DEFAULT" CACHE STRING "LCD type (DEFAULT/ST7565P/ST7565R/ERC12864FSF/ST7920)") set(LCD "DEFAULT" CACHE STRING "LCD type (DEFAULT/ST7565P/ST7565R/ERC12864FSF/ST7920/KS108)")
set(LUA NO) set(LUA NO)
set(PULSES_SRC pulses_avr.cpp) set(PULSES_SRC pulses_avr.cpp)
set(SRC ${SRC} main_avr.cpp) set(SRC ${SRC} main_avr.cpp)

View file

@ -266,7 +266,7 @@ void audioTrimPress(int16_t value)
{ {
if (g_eeGeneral.beepMode >= e_mode_nokeys) { if (g_eeGeneral.beepMode >= e_mode_nokeys) {
#if defined(AUDIO) #if defined(AUDIO)
value = limit(TRIM_MIN, value, TRIM_MAX); value = limit<int16_t>(TRIM_MIN, value, TRIM_MAX);
value >>= 2; value >>= 2;
value += 60; value += 60;
audio.play(value, 6, 1, PLAY_NOW); audio.play(value, 6, 1, PLAY_NOW);
@ -284,12 +284,12 @@ void audioTimerCountdown(uint8_t timer, int value)
} }
#if defined(CPUM2560) #if defined(CPUM2560)
if (g_model.timers[timer].countdownBeep == COUNTDOWN_VOICE) { else if (g_model.timers[timer].countdownBeep == COUNTDOWN_VOICE) {
if (value >= 0 && value <= g_model.timers[timer].countdownStart) { if (value >= 0 && value <= TIMER_COUNTDOWN_START(timer)) {
playNumber(value, 0, 0, 0); playNumber(value, 0, 0);
} }
else if (value == 30 || value == 20) { else if (value == 30 || value == 20) {
playDuration(value, 0, 0); playDuration(value);
} }
} }
#endif #endif

View file

@ -107,6 +107,11 @@ void audioDefevent(uint8_t e);
#define VOICE_AUDIO_BUZZER(v, a, b) AUDIO_BUZZER(a, b) #define VOICE_AUDIO_BUZZER(v, a, b) AUDIO_BUZZER(a, b)
#endif #endif
void audioKeyPress();
void audioKeyError();
void audioTrimPress(int16_t value);
void audioTimerCountdown(uint8_t timer, int value);
#define AUDIO_KEY_PRESS() audioKeyPress() #define AUDIO_KEY_PRESS() audioKeyPress()
#define AUDIO_KEY_ERROR() AUDIO_WARNING2() #define AUDIO_KEY_ERROR() AUDIO_WARNING2()
#define AUDIO_WARNING1() AUDIO_BUZZER(audioDefevent(AU_WARNING1), beep(3)) #define AUDIO_WARNING1() AUDIO_BUZZER(audioDefevent(AU_WARNING1), beep(3))

View file

@ -452,7 +452,7 @@ PACK(struct TimerData {
uint8_t countdownBeep:2; uint8_t countdownBeep:2;
uint8_t minuteBeep:1; uint8_t minuteBeep:1;
uint8_t persistent:2; uint8_t persistent:2;
uint8_t spare:3; uint8_t countdownStart:3;
uint16_t value; uint16_t value;
}); });
#else #else

View file

@ -1371,24 +1371,29 @@ void lcdInvertLine(int8_t y)
} }
} }
#if !defined(BOOT) #define LCD_IMG_FUNCTION(NAME, TYPE, READ_BYTE) \
void lcd_img(coord_t x, coord_t y, const pm_uchar * img, uint8_t idx, LcdFlags att) void NAME(coord_t x, coord_t y, TYPE img, uint8_t idx, LcdFlags att) \
{ { \
const pm_uchar *q = img; TYPE q = img; \
uint8_t w = pgm_read_byte(q++); uint8_t w = READ_BYTE(q++); \
uint8_t hb = (pgm_read_byte(q++)+7)/8; uint8_t hb = (READ_BYTE(q++)+7)/8; \
bool inv = (att & INVERS) ? true : (att & BLINK ? BLINK_ON_PHASE : false); bool inv = (att & INVERS) ? true : (att & BLINK ? BLINK_ON_PHASE : false); \
q += idx*w*hb; q += idx*w*hb; \
for (uint8_t yb = 0; yb < hb; yb++) { for (uint8_t yb = 0; yb < hb; yb++) { \
uint8_t *p = &displayBuf[ (y / 8 + yb) * LCD_W + x ]; uint8_t *p = &displayBuf[ (y / 8 + yb) * LCD_W + x ]; \
for (coord_t i=0; i<w; i++){ for (coord_t i=0; i<w; i++){ \
uint8_t b = pgm_read_byte(q); uint8_t b = READ_BYTE(q); \
q++; q++; \
ASSERT_IN_DISPLAY(p); ASSERT_IN_DISPLAY(p); \
*p++ = inv ? ~b : b; *p++ = inv ? ~b : b; \
} } \
} } \
} }
#if defined(PCBMEGA2560) && !defined(SIMU)
LCD_IMG_FUNCTION(lcd_imgfar, uint_farptr_t, pgm_read_byte_far)
#endif #endif
LCD_IMG_FUNCTION(lcd_img, const pm_uchar *, pgm_read_byte)
#endif #endif

View file

@ -237,6 +237,10 @@ void lcdDrawTelemetryTopBar();
lcdDrawSolidVerticalLine(xx ,yy-ll,ll); \ lcdDrawSolidVerticalLine(xx ,yy-ll,ll); \
lcdDrawSolidVerticalLine(xx+1,yy-ll,ll) lcdDrawSolidVerticalLine(xx+1,yy-ll,ll)
#if defined(PCBMEGA2560) && !defined(SIMU)
void lcd_imgfar(coord_t x, coord_t y, const uint_farptr_t img, uint8_t idx, LcdFlags att); // progmem "far"
#endif
void lcd_img(coord_t x, coord_t y, const pm_uchar * img, uint8_t idx, LcdFlags att=0); void lcd_img(coord_t x, coord_t y, const pm_uchar * img, uint8_t idx, LcdFlags att=0);
void lcdSetRefVolt(unsigned char val); void lcdSetRefVolt(unsigned char val);

View file

@ -292,11 +292,13 @@ void menuModelSetup(uint8_t event)
timer->start = qr.rem + qr.quot*60; timer->start = qr.rem + qr.quot*60;
break; break;
case 2: case 2:
qr.rem -= checkIncDecModel(event, qr.rem+2, 1, 62)-2; qr.rem -= checkIncDecModel(event, qr.rem+2, 1, 62) - 2;
if (timer->start >= qr.rem) { if ((int16_t)timer->start >= qr.rem) {
timer->start -= qr.rem ; timer->start -= qr.rem ;
} }
if ((int32_t)timer->start > 3599) timer->start=3599; // 59:59 if ((int16_t)timer->start > 3599) {
timer->start = 3599; // 59:59
}
break; break;
} }
} }

View file

@ -18,19 +18,44 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include "../../opentx.h" #include "opentx.h"
#if !defined GET_FAR_ADDRESS
#define GET_FAR_ADDRESS(var) \
({ \
uint32_t tmp; \
\
__asm__ __volatile__( \
\
"ldi %A0, lo8(%1)" "\n\t" \
"ldi %B0, hi8(%1)" "\n\t" \
"ldi %C0, hh8(%1)" "\n\t" \
"clr %D0" "\n\t" \
: \
"=d" (tmp) \
: \
"p" (&(var)) \
); \
tmp; \
})
#endif
#if defined(SPLASH) #if defined(SPLASH)
const pm_uchar splashdata[] PROGMEM = { const pm_uchar splashdata[] PROGMEM = {
'S','P','S',0, 'S','P','S',0,
#include "bitmaps/9x/splash.lbm" #include "bitmaps/9x/splash.lbm"
'S','P','E',0 }; 'S','P','E',0 };
const pm_uchar * const splash_lbm = splashdata+4; const pm_uchar * const splash_lbm = splashdata+4;
void drawSplash() void drawSplash()
{ {
lcdClear(); lcdClear();
#if defined(PCBMEGA2560) && !defined(SIMU)
lcd_imgfar(0, 0, pgm_get_far_address(splash_lbm), 0, 0); // use progmem "far" for splash working with all other options enabled
#else
lcd_img(0, 0, splash_lbm, 0, 0); lcd_img(0, 0, splash_lbm, 0, 0);
#endif
#if MENUS_LOCK == 1 #if MENUS_LOCK == 1
if (readonly == false) { if (readonly == false) {

View file

@ -113,7 +113,7 @@ void perMain()
#endif #endif
#if defined(GUI) #if defined(GUI)
const char *warn = warningText; const char * warn = warningText;
bool popupMenuActive = (popupMenuNoItems > 0); bool popupMenuActive = (popupMenuNoItems > 0);
if (IS_LCD_REFRESH_ALLOWED()) { // No need to redraw until lcdRefresh_ST7920(0) below completely refreshes the display. if (IS_LCD_REFRESH_ALLOWED()) { // No need to redraw until lcdRefresh_ST7920(0) below completely refreshes the display.

View file

@ -1426,7 +1426,11 @@ enum AUDIO_SOUNDS {
#endif #endif
#if defined(PCBGRUVIN9X) && defined(VOICE) #if defined(PCBGRUVIN9X) && defined(VOICE)
#include "targets/gruvin9x/somo14d.h" #include "targets/gruvin9x/voice.h"
#endif
#if defined(PCBMEGA2560) && defined(VOICE)
#include "targets/mega2560/voice.h"
#endif #endif
#include "translations.h" #include "translations.h"

View file

@ -0,0 +1,139 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
void lcdSendCtl(uint8_t val)
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
#if defined(LCD_MULTIPLEX)
DDRA = 0xFF; //Set LCD_DAT pins to output
#endif
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
#if defined(LCD_MULTIPLEX)
DDRA = 0x00; //Set LCD_DAT pins to input
#endif
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
const static pm_uchar lcdInitSequence[] PROGMEM =
{
//ST7565 eq. : KS0713, SED1565, S6B1713, SPLC501C, NT7532 /34 /38, TL03245
#if defined(LCD_ST7565R)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA0, //ADC = 0: normal direction (SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA2, //Select LCD bias
0xC8, //SHL = 1: reverse direction (COM64->COM1)
0x2F, //Control power circuit operation VC=VR=VF=1
0x25, //Select int resistance ratio R2 R1 R0 =5
0x81, //Set reference voltage Mode
0x22, //24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
0xAF, //DON = 1: display ON
0x60 //Set the display start line to zero
#elif defined(LCD_ERC12864FSF)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA1, //ADC = 1: reverse direction (SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA3, //Select LCD bias
0xC0, //SHL = 0: normal direction (COM1->COM64)
0x2F, //Control power circuit operation VC=VR=VF=1
0x27, //Select int resistance ratio R2 R1 R0
0x81, //Set reference voltage Mode
0x2D, //24 SV5 SV4 SV3 SV2 SV1 SV0
0xAF //DON = 1: display ON
#else //ST7565P (default 9x LCD)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA1, //ADC = 1: reverse direction(SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA2, //Select LCD bias=0
0xC0, //SHL = 0: normal direction (COM1->COM64)
0x2F, //Control power circuit operation VC=VR=VF=1
0x25, //Select int resistance ratio R2 R1 R0 =5
0x81, //Set reference voltage Mode
0x22, //24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
0xAF //DON = 1: display ON
#endif
};
void lcdInit()
{
LCD_LOCK();
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD reset
_delay_us(2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); //LCD normal operation
_delay_us(1500);
for (uint8_t i=0; i<DIM(lcdInitSequence); i++) {
lcdSendCtl(pgm_read_byte(&lcdInitSequence[i])) ;
}
#if defined(LCD_ERC12864FSF)
g_eeGeneral.contrast = 0x2D;
#else
g_eeGeneral.contrast = 0x22;
#endif
LCD_UNLOCK();
}
void lcdSetRefVolt(uint8_t val)
{
LCD_LOCK();
lcdSendCtl(0x81);
lcdSendCtl(val);
LCD_UNLOCK();
}
void lcdRefresh()
{
LCD_LOCK();
uint8_t * p = displayBuf;
for (uint8_t y=0; y < 8; y++) {
#if defined(LCD_ST7565R)
lcdSendCtl(0x01);
#else
lcdSendCtl(0x04);
#endif
lcdSendCtl(0x10); // Column addr 0
lcdSendCtl( y | 0xB0); //Page addr y
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
#if defined(LCD_MULTIPLEX)
DDRA = 0xFF; // Set LCD_DAT pins to output
#endif
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
for (coord_t x=LCD_W; x>0; --x) {
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
}
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
LCD_UNLOCK();
}

View file

@ -20,244 +20,19 @@
#include "opentx.h" #include "opentx.h"
void lcdSendCtl(uint8_t val)
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
#if defined(LCD_MULTIPLEX)
DDRA = 0xFF; //Set LCD_DAT pins to output
#endif
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
#if defined(LCD_MULTIPLEX)
DDRA = 0x00; //Set LCD_DAT pins to input
#endif
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
#if defined(PCBSTD) && defined(VOICE) #if defined(PCBSTD) && defined(VOICE)
volatile uint8_t LcdLock ; volatile uint8_t LcdLock;
#define LCD_LOCK() LcdLock = 1 #define LCD_LOCK() LcdLock = 1
#define LCD_UNLOCK() LcdLock = 0 #define LCD_UNLOCK() LcdLock = 0
#else #else
#define LCD_LOCK() #define LCD_LOCK()
#define LCD_UNLOCK() #define LCD_UNLOCK()
#endif #endif
const static pm_uchar lcdInitSequence[] PROGMEM = #if defined(LCD_KS108)
{ #include "targets/9x/lcd_ks108_driver.cpp"
//ST7565 eq. : KS0713, SED1565, S6B1713, SPLC501C, NT7532 /34 /38, TL03245
#if defined(LCD_ST7565R)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA0, //ADC = 0: normal direction (SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA2, //Select LCD bias
0xC8, //SHL = 1: reverse direction (COM64->COM1)
0x2F, //Control power circuit operation VC=VR=VF=1
0x25, //Select int resistance ratio R2 R1 R0 =5
0x81, //Set reference voltage Mode
0x22, //24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
0xAF, //DON = 1: display ON
0x60 //Set the display start line to zero
#elif defined(LCD_ERC12864FSF)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA1, //ADC = 1: reverse direction (SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA3, //Select LCD bias
0xC0, //SHL = 0: normal direction (COM1->COM64)
0x2F, //Control power circuit operation VC=VR=VF=1
0x27, //Select int resistance ratio R2 R1 R0
0x81, //Set reference voltage Mode
0x2D, //24 SV5 SV4 SV3 SV2 SV1 SV0
0xAF //DON = 1: display ON
#elif defined(LCD_ST7920) #elif defined(LCD_ST7920)
0x30, //Set 8-bit interface #include "targets/9x/lcd_st7920_driver.cpp"
0x36, //Repeat with graphics bit set to ON
0x0C, //Display ON, cursor and blink OFF
0x01, //Clear display, reset address
0x06 //Display ON, no cursor
#else //ST7565P (default 9x LCD)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA1, //ADC = 1: reverse direction(SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA2, //Select LCD bias=0
0xC0, //SHL = 0: normal direction (COM1->COM64)
0x2F, //Control power circuit operation VC=VR=VF=1
0x25, //Select int resistance ratio R2 R1 R0 =5
0x81, //Set reference voltage Mode
0x22, //24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
0xAF //DON = 1: display ON
#endif
};
void lcdInit()
{
LCD_LOCK();
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD reset
_delay_us(2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); //LCD normal operation
#if defined(LCD_ST7920)
_delay_ms(40);
#else #else
_delay_us(1500); #include "targets/9x/lcd_default_driver.cpp"
#endif #endif
for (uint8_t i=0; i<DIM(lcdInitSequence); i++) {
lcdSendCtl(pgm_read_byte(&lcdInitSequence[i])) ;
#if defined(LCD_ST7920)
_delay_us(80);
#endif
}
#if defined(LCD_ERC12864FSF)
g_eeGeneral.contrast = 0x2D;
#else
g_eeGeneral.contrast = 0x22;
#endif
LCD_UNLOCK();
}
void lcdSetRefVolt(uint8_t val)
{
#if !defined(LCD_ST7920) // No contrast setting for ST7920
LCD_LOCK();
lcdSendCtl(0x81);
lcdSendCtl(val);
LCD_UNLOCK();
#endif
}
#if defined(LCD_ST7920)
void lcdRefresh(){
lcdRefresh_ST7920(1);
}
uint8_t lcdRefresh_ST7920(uint8_t full)
{
#else
void lcdRefresh()
{
#endif
LCD_LOCK();
#if defined(LCD_ST7920)
static uint8_t state;
uint8_t yst,yend;
uint8_t x_addr = 0;
uint8_t y_addr = 0;
uint16_t line_offset = 0;
uint8_t col_offset = 0;
uint8_t bit_count = 0;
uint8_t result;
uint8_t *p;
if(full!=0){
yst=0;
yend=64;
state=0;
}
else{
switch (state){//Since writing to ST7920 is too slow we need to split it to five bands.
default:
case 0:
yst=0;
yend=13;
state=1;
break;
case 1:
yst=13;
yend=26;
state=2;
break;
case 2:
yst=26;
yend=39;
state=3;
break;
case 3:
yst=39;
yend=52;
state=4;
break;
case 4:
yst=52;
yend=64;
state=0;
break;
}
}
for (uint8_t y=yst; y<yend; y++) {
x_addr = 0;
//Convert coordinates to weirdly-arranged 128x64 screen (the ST7920 is mapped for 256x32 displays)
if (y > 31) {
y_addr = y - 32; //Because there are only 31 addressable lines in the ST7920
x_addr += 8; //so we overflow x (7 visible bytes per line) to reach the bottom half
}
else {
y_addr = y;
}
lcdSendCtl( 0x80 | y_addr ); //Set Vertical Address
_delay_us(49);
lcdSendCtl( 0x80 | x_addr ); //Set Horizontal Address
_delay_us(49);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0); //HIGH RS and LOW RW will put the LCD to
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW); //Write data register mode
bit_count = y & 0x07; //Count from 0 bis 7 -> 0=0, 1=1..7=7, 8=0, 9=1...
col_offset = 1 << bit_count; //Build a value for a AND operation with the vorrect bitposition
line_offset = ( y / 8 ) * 128; //On the ST7565 there are 8 lines with each 128 bytes width
for (coord_t x=0; x<16; x++) { //Walk through 16 bytes form left to right (128 Pixel)
p=displayBuf + line_offset + ( x * 8 ); //Calculate the position of the first byte im array
// adressing the bytes sequential and set the bits at the correct position merging them with an OR operation to get all bits in one byte
// the position of the LSB is the right-most position of the byte to the ST7920
result = ((*p++ & col_offset)!=0?0x80:0);
result|= ((*p++ & col_offset)!=0?0x40:0);
result|= ((*p++ & col_offset)!=0?0x20:0);
result|= ((*p++ & col_offset)!=0?0x10:0);
result|= ((*p++ & col_offset)!=0?0x08:0);
result|= ((*p++ & col_offset)!=0?0x04:0);
result|= ((*p++ & col_offset) !=0?0x02:0);
result|= ((*p++ & col_offset)!=0?0x01:0);
PORTA_LCD_DAT = result;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
_delay_us(8);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
_delay_us(49);
}
}
#else //All other LCD
uint8_t * p = displayBuf;
for (uint8_t y=0; y < 8; y++) {
#if defined(LCD_ST7565R)
lcdSendCtl(0x01);
#else
lcdSendCtl(0x04);
#endif
lcdSendCtl(0x10); // Column addr 0
lcdSendCtl( y | 0xB0); //Page addr y
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
#if defined(LCD_MULTIPLEX)
DDRA = 0xFF; // Set LCD_DAT pins to output
#endif
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
for (coord_t x=LCD_W; x>0; --x) {
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
}
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
#endif
LCD_UNLOCK();
#if defined(LCD_ST7920)
return state;
#endif
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define DISPLAY_SET_COLUMN 0x40
#define DISPLAY_SET_PAGE 0xB8
#define DISPLAY_SET_START 0XC0
#define DISPLAY_ON_CMD 0x3F
#define CS1_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1)
#define CS1_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1)
#define CS2_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS2)
#define CS2_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS2)
#define A0_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0)
#define A0_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0)
#define E_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E)
#define E_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E)
void lcdPulseEnable(void)
{
E_on;
_delay_us(4);
E_off;
}
void lcdSendCtl(uint8_t val)
{
PORTA_LCD_DAT = val;
A0_off;
lcdPulseEnable();
A0_on;
}
void lcdInit()
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD reset
_delay_us(20);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); //LCD normal operation
CS1_on;
lcdSendCtl(DISPLAY_ON_CMD);
lcdSendCtl(DISPLAY_SET_START);
CS1_off;
CS2_on;
lcdSendCtl(DISPLAY_ON_CMD);
lcdSendCtl(DISPLAY_SET_START);
CS2_off;
}
void lcdSetRefVolt(uint8_t val)
{
}
void lcdRefreshSide(display_t * p)
{
for (uint8_t page=0; page < 8; page++) {
lcdSendCtl(DISPLAY_SET_COLUMN); // Column addr 0
lcdSendCtl( page | DISPLAY_SET_PAGE); //Page addr
A0_on;
for (coord_t x=64; x>0; --x) {
PORTA_LCD_DAT = *p++;
lcdPulseEnable();
}
p += 64;
}
A0_off;
}
void lcdRefresh()
{
// Right
CS1_on;
lcdRefreshSide(displayBuf);
CS1_off;
// Left
CS2_on;
lcdRefreshSide(displayBuf + 64);
CS2_off;
}

View file

@ -0,0 +1,154 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
void lcdSendCtl(uint8_t val)
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
const static pm_uchar lcdInitSequence[] PROGMEM =
{
0x30, // Set 8-bit interface
0x36, // Repeat with graphics bit set to ON
0x0C, // Display ON, cursor and blink OFF
0x01, // Clear display, reset address
0x06 // Display ON, no cursor
};
void lcdInit()
{
LCD_LOCK();
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD reset
_delay_us(2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); //LCD normal operation
_delay_ms(40);
for (uint8_t i=0; i<DIM(lcdInitSequence); i++) {
lcdSendCtl(pgm_read_byte(&lcdInitSequence[i])) ;
_delay_us(80);
}
g_eeGeneral.contrast = 0x22;
LCD_UNLOCK();
}
void lcdSetRefVolt(uint8_t val)
{
}
uint8_t lcdRefresh_ST7920(uint8_t full)
{
LCD_LOCK();
static uint8_t state;
uint8_t yst,yend;
uint8_t x_addr = 0;
uint8_t y_addr = 0;
uint16_t line_offset = 0;
uint8_t col_offset = 0;
uint8_t bit_count = 0;
uint8_t result;
uint8_t * p;
if (full != 0) {
yst=0;
yend=64;
state=0;
}
else {
switch (state) { // Since writing to ST7920 is too slow we need to split it to five bands.
default:
case 0:
yst=0;
yend=13;
state=1;
break;
case 1:
yst=13;
yend=26;
state=2;
break;
case 2:
yst=26;
yend=39;
state=3;
break;
case 3:
yst=39;
yend=52;
state=4;
break;
case 4:
yst=52;
yend=64;
state=0;
break;
}
}
for (uint8_t y=yst; y<yend; y++) {
x_addr = 0;
//Convert coordinates to weirdly-arranged 128x64 screen (the ST7920 is mapped for 256x32 displays)
if (y > 31) {
y_addr = y - 32; //Because there are only 31 addressable lines in the ST7920
x_addr += 8; //so we overflow x (7 visible bytes per line) to reach the bottom half
}
else {
y_addr = y;
}
lcdSendCtl( 0x80 | y_addr ); //Set Vertical Address
_delay_us(49);
lcdSendCtl( 0x80 | x_addr ); //Set Horizontal Address
_delay_us(49);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0); //HIGH RS and LOW RW will put the LCD to
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW); //Write data register mode
bit_count = y & 0x07; //Count from 0 bis 7 -> 0=0, 1=1..7=7, 8=0, 9=1...
col_offset = 1 << bit_count; //Build a value for a AND operation with the vorrect bitposition
line_offset = ( y / 8 ) * 128; //On the ST7565 there are 8 lines with each 128 bytes width
for (coord_t x=0; x<16; x++) { //Walk through 16 bytes form left to right (128 Pixel)
p = displayBuf + line_offset + ( x * 8 ); //Calculate the position of the first byte im array
// adressing the bytes sequential and set the bits at the correct position merging them with an OR operation to get all bits in one byte
// the position of the LSB is the right-most position of the byte to the ST7920
result = ((*p++ & col_offset)!=0?0x80:0);
result |= ((*p++ & col_offset)!=0?0x40:0);
result |= ((*p++ & col_offset)!=0?0x20:0);
result |= ((*p++ & col_offset)!=0?0x10:0);
result |= ((*p++ & col_offset)!=0?0x08:0);
result |= ((*p++ & col_offset)!=0?0x04:0);
result |= ((*p++ & col_offset) !=0?0x02:0);
result |= ((*p++ & col_offset)!=0?0x01:0);
PORTA_LCD_DAT = result;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
_delay_us(8);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
_delay_us(49);
}
}
LCD_UNLOCK();
return state;
}
void lcdRefresh()
{
lcdRefresh_ST7920(1);
}

View file

@ -25,16 +25,16 @@ inline void boardInit()
{ {
// Set up I/O port data directions and initial states (unused pin setting : input, pull-up on) // Set up I/O port data directions and initial states (unused pin setting : input, pull-up on)
DDRA = 0b11111111; PORTA = 0b00000000; // LCD data DDRA = 0b11111111; PORTA = 0b00000000; // LCD data
DDRB = 0b01110111; PORTB = 0b10101111; // 7:N/A 6:PPM_OUT, 5:SimCTRL, 4:Buzzer, SDCARD[3:MISO 2:MOSI 1:SCK 0:CS] DDRB = 0b01110111; PORTB = 0b00101111; // 7:SOMOBusy, 6:PPM_OUT, 5:SimCTRL, 4:Buzzer, SDCARD[3:MISO 2:MOSI 1:SCK 0:CS]
DDRC = 0b11111100; PORTC = 0b00000011; // 7-3:LCD, 2:BackLight, 1:ID2_SW, 0:ID1_SW DDRC = 0b11111100; PORTC = 0b00000011; // 7-3:LCD, 2:BackLight, 1:ID2_SW, 0:ID1_SW
DDRD = 0b00000000; PORTD = 0b11111100; // 7:AilDR_SW, 6:N/A, 5:N/A, 4:N/A, 3:RENC2_B, 2:RENC2_A, 1:I2C_SDA, 0:I2C_SCL DDRD = 0b00000000; PORTD = 0b11111100; // 7:AilDR_SW, 6:N/A, 5:N/A, 4:N/A, 3:RENC2_B, 2:RENC2_A, 1:I2C_SDA, 0:I2C_SCL
DDRE = 0b00000010; PORTE = 0b01111100; // 7:PPM_IN, 6:N/A, 5:RENC1_B, 4:RENC1_A, 3:N/A, 2:N/A, 1:TELEM_TX, 0:TELEM_RX DDRE = 0b00001010; PORTE = 0b01110100; // 7:PPM_IN, 6:N/A, 5:RENC1_B, 4:RENC1_A, 3:SOMOData, 2:N/A, 1:TELEM_TX, 0:TELEM_RX
DDRF = 0b00000000; PORTF = 0b11111111; // 7-0:Trim switch inputs DDRF = 0b00000000; PORTF = 0b11111111; // 7-0:Trim switch inputs
DDRG = 0b00000000; PORTG = 0b11111111; // 7:N/A, 6:N/A, 5:N/A, 4:N/A, 3:N/A, 2:TCut_SW, 1:Gear_SW, 0: RudDr_SW DDRG = 0b00100000; PORTG = 0b11011111; // 7:N/A, 6:N/A, 5:SOMOClock, 4:N/A, 3:N/A, 2:TCut_SW, 1:Gear_SW, 0: RudDr_SW
#if defined(PCBMEGA2560) && defined(DEBUG) #if defined(DEBUG)
DDRH = 0b01011000; PORTH = 0b11110110; // 7:N/A, 6:RF_Activated, 5:DSC_Activated, 4:Hold_Power, 3:Speaker, 2:N/A, 1:N/A, 0:Haptic DDRH = 0b01011010; PORTH = 0b11110100; // 7:N/A, 6:RF_Activated, 5:DSC_Activated, 4:Hold_Power, 3:Speaker, 2:N/A, 1:SOMOReset, 0:Haptic
#else #else
DDRH = 0b00011000; PORTH = 0b11110110; // 7:N/A, 6:RF_Activated, 5:DSC_Activated, 4:Hold_Power, 3:Speaker, 2:N/A, 1:N/A, 0:Haptic DDRH = 0b00011010; PORTH = 0b11110100; // 7:N/A, 6:RF_Activated, 5:DSC_Activated, 4:Hold_Power, 3:Speaker, 2:N/A, 1:SOMOReset, 0:Haptic
#endif #endif
DDRJ = 0b00000000; PORTJ = 0b11111111; // 7:N/A, 6:N/A, 5:N/A, 4:N/A, 3:N/A, 2:N/A, 1:RENC2_push, 0:RENC1_push DDRJ = 0b00000000; PORTJ = 0b11111111; // 7:N/A, 6:N/A, 5:N/A, 4:N/A, 3:N/A, 2:N/A, 1:RENC2_push, 0:RENC1_push
DDRK = 0b00000000; PORTK = 0b00000000; // Analogic input (no pull-ups) DDRK = 0b00000000; PORTK = 0b00000000; // Analogic input (no pull-ups)
@ -49,16 +49,18 @@ inline void boardInit()
OCR2A = 156; OCR2A = 156;
TIMSK2 |= (1<<OCIE2A) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts TIMSK2 |= (1<<OCIE2A) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts
#if defined(AUDIO)
// TIMER4 set into CTC mode, prescaler 16MHz/64=250 kHz // TIMER4 set into CTC mode, prescaler 16MHz/64=250 kHz
// Used for audio tone generation // Used for audio tone generation
TCCR4B = (1<<WGM42) | (0b011 << CS00); TCCR4B = (1<<WGM42) | (0b011 << CS40);
TCCR4A = 0x00; TCCR4A = 0x00;
#endif
#if defined (VOICE) // OLD FROM GRUVIN9X, TO REWRITE #if defined(VOICE)
// SOMO set-up // SOMO set-up, with TIMER5
OCR4A = 0x1F4; //2ms OCR5A = 0x1F4; //2ms
TCCR4B = (1 << WGM42) | (0b011 << CS40); // CTC OCR1A, 16MHz / 64 (4us ticks) TCCR5B = (1 << WGM52) | (0b011 << CS50); // CTC OCR5A
TIMSK4 |= (1<<OCIE4A); // Start the interrupt so the unit reset can occur TIMSK5 |= (1<<OCIE5A); // Start the interrupt so the unit reset can occur
#endif #endif
/* Rotary encoder interrupt set-up */ /* Rotary encoder interrupt set-up */

View file

@ -84,46 +84,54 @@ void sdPoll10ms(void);
#endif #endif
// Switchs driver // Switchs driver
# define INP_C_ID2 1 #define INP_C_ID2 1
# define INP_C_ID1 0 #define INP_C_ID1 0
# define INP_D_AileDR 7 #define INP_D_AileDR 7
# define INP_G_ThrCt 2 #define INP_G_ThrCt 2
# define INP_G_Gear 1 #define INP_G_Gear 1
# define INP_G_RuddDR 0 #define INP_G_RuddDR 0
# define INP_L_ElevDR 6 #define INP_L_ElevDR 6
# define INP_L_Trainer 7 #define INP_L_Trainer 7
// Servitudes driver // Servitudes driver
//#define INP_E_PPM_IN 7 //reserved PPM_IN #define INP_E_PPM_IN 7 //not used (reserved)
# define OUT_B_PPM 6 #define INP_B_14DBUSY 7 //somo14d, not used (reserved)
# define OUT_B_SIM_CTL 5 #define OUT_B_PPM 6
# define OUT_B_BUZZER 4 #define OUT_B_SIM_CTL 5
# define INP_D_I2C_SCL 1 #define OUT_B_BUZZER 4
# define INP_D_I2C_SDA 0 #define INP_D_I2C_SCL 1
# define INP_E_TELEM_RX 1 #define INP_D_I2C_SDA 0
# define OUT_E_TELEM_TX 0 #define OUT_E_14DDATA 3 //somo14d
# define INP_H_RF_Activated 6 #define INP_E_TELEM_RX 1
//#define INP_H_ 5 //reserved DSC_Activated, for pwrCheck() #define OUT_E_TELEM_TX 0
//#define INP_H_ 4 //reserved Hold_Power, for pwrCheck() #define OUT_G_14DCLK 5 //somo14d
# define OUT_H_Speaker 3 #define INP_H_RF_Activated 6
# define OUT_H_HAPTIC 0 #define INP_H_DSC_Activated 5 //not used, reserved for pwrCheck()
#define INP_H_Hold_Power 4 //not used, reserved for pwrCheck()
#define OUT_H_Speaker 3
#define OUT_H_14DRESET 1 //somo14d
#define OUT_H_HAPTIC 0
// Rotary encoders driver // Rotary encoders driver
# define INP_E_ROT_ENC_1_A 4 #define INP_E_ROT_ENC_1_A 4
# define INP_E_ROT_ENC_1_B 5 #define INP_E_ROT_ENC_1_B 5
# define INP_D_ROT_ENC_2_A 2 #define INP_D_ROT_ENC_2_A 2
# define INP_D_ROT_ENC_2_B 3 #define INP_D_ROT_ENC_2_B 3
# define INP_J_ROT_ENC_1_PUSH 0 #define INP_J_ROT_ENC_1_PUSH 0
# define INP_J_ROT_ENC_2_PUSH 1 #define INP_J_ROT_ENC_2_PUSH 1
# define REA_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_1_PUSH)) #define REA_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_1_PUSH))
# define REB_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_2_PUSH)) #define REB_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_2_PUSH))
# define ROTENC_DOWN() (REA_DOWN() || REB_DOWN()) #define ROTENC_DOWN() (REA_DOWN() || REB_DOWN())
// LCD driver // LCD driver
#define PORTA_LCD_DAT PORTA #define PORTA_LCD_DAT PORTA
#define PORTC_LCD_CTRL PORTC #define PORTC_LCD_CTRL PORTC
#define OUT_C_LCD_E 7 #if defined(LCD_KS108) // (For KS108 LCd only) MEGA R/W pin always at 0 state in Opentx then
#define OUT_C_LCD_CS2 6 //Use this pin to control second KS108
#else // And connect LCD R/W pin to ground via a 1k resistor
#define OUT_C_LCD_RnW 6 #define OUT_C_LCD_RnW 6
#endif
#define OUT_C_LCD_E 7
#define OUT_C_LCD_A0 5 #define OUT_C_LCD_A0 5
#define OUT_C_LCD_RES 4 #define OUT_C_LCD_RES 4
#define OUT_C_LCD_CS1 3 #define OUT_C_LCD_CS1 3
@ -153,8 +161,22 @@ void pwrOff();
#define buzzerOff() PORTB &= ~(1 << OUT_B_BUZZER) #define buzzerOff() PORTB &= ~(1 << OUT_B_BUZZER)
// Speaker driver // Speaker driver
#if defined(AUDIO)
#define speakerOn() TCCR4A |= (1 << COM4A0) #define speakerOn() TCCR4A |= (1 << COM4A0)
#define speakerOff() TCCR4A &= ~(1 << COM4A0) #define speakerOff() TCCR4A &= ~(1 << COM4A0)
#endif
// Voice driver
#if defined(VOICE)
#define WTV20SD_Clock_on PORTG |= (1<<OUT_G_14DCLK)
#define WTV20SD_Clock_off PORTG &= ~(1<<OUT_G_14DCLK)
#define WTV20SD_Data_on PORTE |= (1<<OUT_E_14DDATA)
#define WTV20SD_Data_off PORTE &= ~(1<<OUT_E_14DDATA)
#define WTV20SD_Reset_on PORTH |= (1<<OUT_H_14DRESET)
#define WTV20SD_Reset_off PORTH &= ~(1<<OUT_H_14DRESET)
#define WTV20SD_BUSY (PINB & 0x80)
#define WTV20SD_CLK (PING & 0x20)
#endif
// EEPROM driver // EEPROM driver
#if !defined(SIMU) #if !defined(SIMU)

View file

@ -0,0 +1,164 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
// driver adapted from somo14d driver for gruvin9x board for driving WTV20SDMini module
#include "../../opentx.h"
// Start and stop bits need to be 2ms in duration. Start bit is low, stop bit is high
#define WTV20SD_STOP_TIME 68 // This is the needed 2ms (4) + 30ms (60) to allow for the
// point at which the busy flag is checkable + 2ms for saftey (4)
#define WTV20SD_START_TIME 5 // The 2ms of a stop/start bit
enum WTV20SD_State
{
PAUSE,
SENDSTART,
SENDDATA,
SENDSTOP
};
#define QUEUE_LENGTH 10
uint16_t WTV20SD_playlist[QUEUE_LENGTH] = {0};
volatile uint8_t WTV20SD_InputIndex = 0;
uint8_t WTV20SD_PlayIndex = 0;
uint8_t Startstop = WTV20SD_START_TIME;
uint16_t WTV20SD_current = 0;
uint8_t state = PAUSE;
void WTV20SD_sendstart()
{
WTV20SD_Clock_off; // Start Bit, CLK low for 2ms
--Startstop;
if (!Startstop) state = SENDDATA;
}
void WTV20SD_senddata()
{
static uint8_t i = 0;
if (!WTV20SD_CLK) {
// Only change data when the CLK is low
if (WTV20SD_current & 0x8000) {
WTV20SD_Data_on; // Data high
}
WTV20SD_current = (WTV20SD_current<<1);
++i;
_delay_us(1); // Data setup delay
WTV20SD_Clock_on; // CLK high
}
else {
// Don't alter after sending last bit in preparation for sending stop bit
WTV20SD_Clock_off; // CLK low
WTV20SD_Data_off; // Data low
}
if (i == 16) { i = 0; Startstop = WTV20SD_STOP_TIME; state = SENDSTOP; }
}
void WTV20SD_sendstop()
{
WTV20SD_Data_off; // Data low
WTV20SD_Clock_on; // Stop Bit, CLK high for 2ms
--Startstop;
if (!Startstop && !WTV20SD_BUSY) state = PAUSE;
}
void pushPrompt(uint16_t prompt)
{
// if mute active => no voice
if (g_eeGeneral.beepMode == e_mode_quiet) return;
/* Load playlist and activate interrupt */
WTV20SD_playlist[WTV20SD_InputIndex] = prompt;
++WTV20SD_InputIndex;
WTV20SD_InputIndex %= QUEUE_LENGTH;
if (!isPlaying()) {
TIMSK5 |= (1<<OCIE5A); // enable interrupts on Output Compare A Match
}
}
uint8_t isPlaying()
{
/* interrupts active on Output Compare A Match ? */
#if defined(SIMU)
return false;
#else
return (TIMSK5 & (1<<OCIE5A));
#endif
}
#if !defined(SIMU)
ISR(TIMER5_COMPA_vect) // every 0.5ms normally, every 2ms during startup reset
{
static uint8_t reset_dly=4;
static uint8_t reset_pause=150;
if (reset_dly) {
OCR5A=0x1f4;
reset_dly--;
WTV20SD_Reset_off;
WTV20SD_Data_off;
WTV20SD_Clock_on;
} // RESET low
else if (reset_pause) {
OCR5A=0x1f4;
reset_pause--;
WTV20SD_Reset_on;
} // RESET high
else {
OCR5A = 0x7d; // another 0.5ms
if (state == PAUSE) {
if (WTV20SD_PlayIndex == WTV20SD_InputIndex) {
TIMSK5 &= ~(1<<OCIE5A); // stop reentrance
TCNT5=0; // reset timer
return; // nothing else to play
}
else {
WTV20SD_current = WTV20SD_playlist[WTV20SD_PlayIndex];
++WTV20SD_PlayIndex;
WTV20SD_PlayIndex %= QUEUE_LENGTH;
Startstop = WTV20SD_START_TIME;
state = SENDSTART;
}
} // end PAUSE
if (state == SENDSTART) {
WTV20SD_sendstart();
return;
}
if (state == SENDDATA) {
WTV20SD_senddata();
return;
}
if (state == SENDSTOP) {
WTV20SD_sendstop();
return;
}
}
}
#endif

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define PROMPT_CUSTOM_BASE 0
#define PROMPT_I18N_BASE 256
#define PROMPT_SYSTEM_BASE 480
extern void pushPrompt(uint16_t prompt);
extern uint8_t isPlaying();
#define I18N_PLAY_FUNCTION(lng, x, ...) void x(__VA_ARGS__)
#define PLAY_FUNCTION(x, ...) void x(__VA_ARGS__)
#define PUSH_CUSTOM_PROMPT(p, id) pushPrompt(PROMPT_CUSTOM_BASE+(p))
#define PUSH_NUMBER_PROMPT(p) pushPrompt(PROMPT_I18N_BASE+(p))
#define PUSH_SYSTEM_PROMPT(p) pushPrompt(PROMPT_SYSTEM_BASE+(p))
#define PLAY_NUMBER(n, u, a) playNumber((n), (u), (a))
#define PLAY_DURATION(d, att) playDuration((d))
#define PLAY_DURATION_ATT
#define PLAY_TIME
#define IS_PLAY_TIME() (0)
#define IS_PLAYING(id) isPlaying()
#define PLAY_VALUE(v, id) playValue((v))
#define VOLUME_LEVEL_MAX 7
#define VOLUME_LEVEL_DEF 7
#define setScaledVolume(v)

View file

@ -39,14 +39,14 @@ make -j2 gtests ; ./gtests
# OpenTX on Mega2560 with Mavlink telemetry # OpenTX on Mega2560 with Mavlink telemetry
rm -rf * rm -rf *
cmake ${COMMON_OPTIONS} -DPCB=MEGA2560 -DEXT=MAVLINK -DHELI=YES ${SRCDIR} cmake ${COMMON_OPTIONS} -DPCB=MEGA2560 -DEXT=MAVLINK -DHELI=YES -DAUDIO=YES -DVOICE=YES ${SRCDIR}
make -j2 firmware make -j2 firmware
make -j2 simu make -j2 simu
make -j2 gtests ; ./gtests make -j2 gtests ; ./gtests
# OpenTX on gruvin9x board # OpenTX on gruvin9x board
rm -rf * rm -rf *
cmake ${COMMON_OPTIONS} -DPCB=GRUVIN9X -DHELI=YES ${SRCDIR} cmake ${COMMON_OPTIONS} -DPCB=GRUVIN9X -DHELI=YES -DAUDIO=YES -DVOICE=YES ${SRCDIR}
make -j2 firmware make -j2 firmware
make -j2 simu make -j2 simu
make -j2 gtests ; ./gtests make -j2 gtests ; ./gtests