diff --git a/src/Makefile b/src/Makefile
index 56bc5f1871..225ba80bf3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -14,7 +14,7 @@ default: $(TARGET)
ALLTARGETS = $(filter-out common,$(notdir $(wildcard target/tx/*/*)))
# The supported transmitters
-TXS ?= devo6 devo7e devo7e-256 devo8 devo10 devo12e devo12 devof7 devof7-XMS devof4 devof4-XMS devof12e devof12e-XMS at9 at10 t8sg t8sg_v2 t8sg_v2_plus ir8m
+TXS ?= devo6 devo7e devo7e-256 devo8 devo10 devo12e devo12 devof7 devof7-XMS devof4 devof4-XMS devof12e devof12e-XMS at9 at10 t8sg_v1 t8sg_v2 t8sg_v2_plus ir8m
#Filter non-existant emus
EMUS = $(foreach dir,$(TXS:%=emu_%),$(if $(wildcard target/$(dir)),$(dir),))
diff --git a/src/pages/128x64x1/tx_configure.c b/src/pages/128x64x1/tx_configure.c
index c39af0c063..31fea33a04 100644
--- a/src/pages/128x64x1/tx_configure.c
+++ b/src/pages/128x64x1/tx_configure.c
@@ -52,6 +52,10 @@ static u16 current_selected = 0; // do not put current_selected into pagemem as
static int size_cb(int absrow, void *data)
{
(void)data;
+ if (absrow >= ITEM_BACKLIGHT && HAS_OLED_DISPLAY) {
+ // This will hide the backlight row
+ absrow++;
+ }
switch(absrow) {
#if SUPPORT_MULTI_LANGUAGE
case ITEM_LANG:
@@ -59,11 +63,7 @@ static int size_cb(int absrow, void *data)
case ITEM_MODE:
#endif
case ITEM_BUZZ:
-#if !HAS_OLED_DISPLAY
- case ITEM_BACKLIGHT:
-#else
case ITEM_CONTRAST:
-#endif
case ITEM_PREALERT:
case ITEM_TELEMTEMP:
return 2;
@@ -88,6 +88,10 @@ static int row_cb(int absrow, int relrow, int y, void *data)
void *but_str = NULL;
u8 x = LARGE_SEL_X_OFFSET;
+ if (absrow >= ITEM_BACKLIGHT && HAS_OLED_DISPLAY) {
+ // This will hide the backlight row
+ absrow++;
+ }
switch(absrow) {
#if SUPPORT_MULTI_LANGUAGE
case ITEM_LANG:
@@ -142,20 +146,15 @@ static int row_cb(int absrow, int relrow, int y, void *data)
label = _tr_noop("PwrDn alert");
value = _music_shutdown_cb; x = MED_SEL_X_OFFSET;
break;
-#if !HAS_OLED_DISPLAY
- case ITEM_BACKLIGHT:
- title = _tr_noop("LCD settings");
- label = _tr_noop("Backlight");
- value = backlight_select_cb; x = SMALL_SEL_X_OFFSET;
- break;
-#endif
case ITEM_CONTRAST:
-#if HAS_OLED_DISPLAY
title = _tr_noop("LCD settings");
-#endif
label = _tr_noop("Contrast");
value = _contrast_select_cb; x = SMALL_SEL_X_OFFSET;
break;
+ case ITEM_BACKLIGHT:
+ label = _tr_noop("Backlight");
+ value = backlight_select_cb; x = SMALL_SEL_X_OFFSET;
+ break;
case ITEM_DIMTIME:
label = _tr_noop("Dimmer time");
value = auto_dimmer_time_cb; x = SMALL_SEL_X_OFFSET;
@@ -229,9 +228,9 @@ static const char *_contrast_select_cb(guiObject_t *obj, int dir, void *data)
0, 10, dir, 1, 1, &changed);
if (changed) {
LCD_Contrast(Transmitter.contrast);
-#if HAS_OLED_DISPLAY
- Transmitter.backlight = Transmitter.contrast;
-#endif
+ if (HAS_OLED_DISPLAY) {
+ Transmitter.backlight = Transmitter.contrast;
+ }
}
if (Transmitter.contrast == 0)
return _tr("Off");
diff --git a/src/pages/common/_tx_configure.c b/src/pages/common/_tx_configure.c
index 12d988e50a..cc72fbcf6f 100644
--- a/src/pages/common/_tx_configure.c
+++ b/src/pages/common/_tx_configure.c
@@ -31,10 +31,8 @@ enum {
ITEM_BATT,
ITEM_ALARM_INTV,
ITEM_PWRDN_ALARM,
-#if !HAS_OLED_DISPLAY
- ITEM_BACKLIGHT,
-#endif
ITEM_CONTRAST,
+ ITEM_BACKLIGHT,
ITEM_DIMTIME,
ITEM_DIMVAL,
ITEM_PREALERT,
@@ -184,7 +182,6 @@ static const char *modeselect_cb(guiObject_t *obj, int dir, void *data)
return tempstring;
}
-#if !HAS_OLED_DISPLAY
static const char *backlight_select_cb(guiObject_t *obj, int dir, void *data)
{
(void)data;
@@ -199,7 +196,6 @@ static const char *backlight_select_cb(guiObject_t *obj, int dir, void *data)
sprintf(tempstring, "%d", Transmitter.backlight);
return tempstring;
}
-#endif
static const char *common_select_cb(guiObject_t *obj, int dir, void *data)
{
diff --git a/src/target/drivers/backlight/backlight.c b/src/target/drivers/backlight/backlight.c
index 0984fe67a8..f1c2f60009 100644
--- a/src/target/drivers/backlight/backlight.c
+++ b/src/target/drivers/backlight/backlight.c
@@ -15,47 +15,25 @@
#include "common.h"
-#if !HAS_OLED_DISPLAY
#include "target/drivers/mcu/stm32/rcc.h"
#include "target/drivers/mcu/stm32/tim.h"
+#include "oled.h"
+#include "lcd.h"
void BACKLIGHT_Init()
{
- rcc_periph_clock_enable(get_rcc_from_pin(BACKLIGHT_TIM.pin));
- GPIO_setup_input(BACKLIGHT_TIM.pin, ITYPE_FLOAT);
-
- // Configure Backlight PWM
- rcc_periph_clock_enable(get_rcc_from_port(BACKLIGHT_TIM.tim));
- timer_set_mode(BACKLIGHT_TIM.tim, TIM_CR1_CKD_CK_INT,
- TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
- timer_set_period(BACKLIGHT_TIM.tim, 0x2CF);
- timer_set_prescaler(BACKLIGHT_TIM.tim, 0);
- timer_generate_event(BACKLIGHT_TIM.tim, TIM_EGR_UG);
- timer_set_oc_mode(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch), TIM_OCM_PWM1);
- timer_enable_oc_preload(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch));
-
- timer_set_oc_polarity_high(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch));
- timer_enable_oc_output(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch));
-
- timer_enable_preload(BACKLIGHT_TIM.tim);
+ if (HAS_OLED_DISPLAY) {
+ _oled_backlight_init();
+ } else {
+ _lcd_backlight_init();
+ }
}
void BACKLIGHT_Brightness(unsigned brightness)
{
- timer_disable_counter(BACKLIGHT_TIM.tim);
- if (brightness == 0) {
- // Turn off Backlight
- GPIO_setup_input(BACKLIGHT_TIM.pin, ITYPE_FLOAT);
- } else if (brightness > 9) {
- // Turn on Backlight full
- GPIO_setup_output(BACKLIGHT_TIM.pin, OTYPE_PUSHPULL);
- GPIO_pin_set(BACKLIGHT_TIM.pin);
+ if (HAS_OLED_DISPLAY) {
+ _oled_backlight_brightness(brightness);
} else {
- GPIO_setup_output_af(BACKLIGHT_TIM.pin, OTYPE_PUSHPULL, BACKLIGHT_TIM.tim);
- u32 duty_cycle = 720 * brightness / 10;
- timer_set_oc_value(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch), duty_cycle);
- timer_enable_counter(BACKLIGHT_TIM.tim);
+ _lcd_backlight_brightness(brightness);
}
}
-
-#endif // !HAS_OLED_DISPLAY
diff --git a/src/target/drivers/backlight/lcd.h b/src/target/drivers/backlight/lcd.h
new file mode 100644
index 0000000000..1b5084b0c9
--- /dev/null
+++ b/src/target/drivers/backlight/lcd.h
@@ -0,0 +1,39 @@
+
+static void _lcd_backlight_init()
+{
+ rcc_periph_clock_enable(get_rcc_from_pin(BACKLIGHT_TIM.pin));
+ GPIO_setup_input(BACKLIGHT_TIM.pin, ITYPE_FLOAT);
+
+ // Configure Backlight PWM
+ rcc_periph_clock_enable(get_rcc_from_port(BACKLIGHT_TIM.tim));
+ timer_set_mode(BACKLIGHT_TIM.tim, TIM_CR1_CKD_CK_INT,
+ TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+ timer_set_period(BACKLIGHT_TIM.tim, 0x2CF);
+ timer_set_prescaler(BACKLIGHT_TIM.tim, 0);
+ timer_generate_event(BACKLIGHT_TIM.tim, TIM_EGR_UG);
+ timer_set_oc_mode(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch), TIM_OCM_PWM1);
+ timer_enable_oc_preload(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch));
+
+ timer_set_oc_polarity_high(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch));
+ timer_enable_oc_output(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch));
+
+ timer_enable_preload(BACKLIGHT_TIM.tim);
+}
+
+static void _lcd_backlight_brightness(unsigned brightness)
+{
+ timer_disable_counter(BACKLIGHT_TIM.tim);
+ if (brightness == 0) {
+ // Turn off Backlight
+ GPIO_setup_input(BACKLIGHT_TIM.pin, ITYPE_FLOAT);
+ } else if (brightness > 9) {
+ // Turn on Backlight full
+ GPIO_setup_output(BACKLIGHT_TIM.pin, OTYPE_PUSHPULL);
+ GPIO_pin_set(BACKLIGHT_TIM.pin);
+ } else {
+ GPIO_setup_output_af(BACKLIGHT_TIM.pin, OTYPE_PUSHPULL, BACKLIGHT_TIM.tim);
+ u32 duty_cycle = 720 * brightness / 10;
+ timer_set_oc_value(BACKLIGHT_TIM.tim, TIM_OCx(BACKLIGHT_TIM.ch), duty_cycle);
+ timer_enable_counter(BACKLIGHT_TIM.tim);
+ }
+}
diff --git a/src/target/drivers/backlight/oled.h b/src/target/drivers/backlight/oled.h
new file mode 100644
index 0000000000..8058726c20
--- /dev/null
+++ b/src/target/drivers/backlight/oled.h
@@ -0,0 +1,28 @@
+/*
+ This project is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Deviation 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.
+
+ You should have received a copy of the GNU General Public License
+ along with Deviation. If not, see .
+*/
+
+/* These are defined in 128x64x1_oled_ssd1306.h */
+void OLED_Backlight();
+void OLED_Backlight_Brightness(unsigned brightness);
+
+static void _oled_backlight_init()
+{
+ OLED_Backlight();
+}
+
+static void _oled_backlight_brightness(unsigned brightness)
+{
+ OLED_Backlight_Brightness(brightness);
+}
diff --git a/src/target/drivers/display/8080/128x64x1.c b/src/target/drivers/display/8080/128x64x1.c
new file mode 100644
index 0000000000..6e040f4f3b
--- /dev/null
+++ b/src/target/drivers/display/8080/128x64x1.c
@@ -0,0 +1,55 @@
+/*
+ This project is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Deviation 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.
+
+ You should have received a copy of the GNU General Public License
+ along with Deviation. If not, see .
+*/
+#include
+#include
+#include "common.h"
+#include "gui/gui.h"
+#include "target/drivers/mcu/stm32/fsmc.h"
+
+#define LCD_CONTRAST_FUNC(contrast) (0x20 + contrast * 0xC / 10)
+
+#define LCD_CMD_ADDR ((uint32_t)FSMC_BANK1_BASE) /* Register Address */
+#define LCD_DATA_ADDR ((uint32_t)FSMC_BANK1_BASE + 0x10000) /* Data Address */
+
+#define LCD_CMD *(volatile uint8_t *)(LCD_CMD_ADDR)
+#define LCD_DATA *(volatile uint8_t *)(LCD_DATA_ADDR)
+
+inline static void LCD_Cmd(unsigned cmd)
+{
+ LCD_CMD = cmd;
+}
+
+inline static void LCD_Data(unsigned data)
+{
+ LCD_DATA = data;
+}
+#define LCD_CONTRAST_FUNC(contrast) (0x20 + contrast * 0xC / 10)
+
+static void lcd_init_ports()
+{
+ _fsmc_init(
+ 8,
+ 0x10000, /*only bit 16 of addr */
+ FSMC_NOE | FSMC_NWE | FSMC_NE1, /* Not connected */
+ FSMC_BANK1,
+ /* Normal mode, write enable, 8 bit access, SRAM, bank enabled */
+ FSMC_BCR_FACCEN | FSMC_BCR_WREN | FSMC_BCR_MBKEN,
+ /* Data Setup > 90ns, Address Setup = 2xHCLK to ensure no output collision in 6800
+ mode since LCD E and !CS always active */
+ FSMC_BTR_DATASTx(7) | FSMC_BTR_ADDHLDx(0) | FSMC_BTR_ADDSETx(2),
+ 0);
+}
+
+#include "../spi/128x64x1_common.h"
diff --git a/src/target/drivers/display/8080/128x64x1_nt7538.c b/src/target/drivers/display/8080/128x64x1_nt7538.c
deleted file mode 100644
index 2a971f2a32..0000000000
--- a/src/target/drivers/display/8080/128x64x1_nt7538.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- This project is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Deviation 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.
-
- You should have received a copy of the GNU General Public License
- along with Deviation. If not, see .
-*/
-#include
-#include
-#include "common.h"
-#include "gui/gui.h"
-#include "target/drivers/mcu/stm32/fsmc.h"
-
-#define LCD_CMD_ADDR ((uint32_t)FSMC_BANK1_BASE) /* Register Address */
-#define LCD_DATA_ADDR ((uint32_t)FSMC_BANK1_BASE + 0x10000) /* Data Address */
-
-#define LCD_CMD *(volatile uint8_t *)(LCD_CMD_ADDR)
-#define LCD_DATA *(volatile uint8_t *)(LCD_DATA_ADDR)
-
-//The screen is 129 characters, but we'll only expoise 128 of them
-#define PHY_LCD_WIDTH 129
-#define LCD_PAGES 8
-static u8 img[PHY_LCD_WIDTH * LCD_PAGES];
-static u8 dirty[PHY_LCD_WIDTH];
-static unsigned int xstart, xend; // After introducing logical view for devo10, the coordinate can be >= 5000
-static unsigned int xpos, ypos;
-static s8 dir;
-
-static void lcd_display(uint8_t on)
-{
- LCD_CMD = 0xAE | (on ? 1 : 0);
-}
-
-static void lcd_set_page_address(uint8_t page)
-{
- LCD_CMD = 0xB0 | (page & 0x07);
-}
-
-static void lcd_set_column_address(uint8_t column)
-{
- LCD_CMD = 0x10 | ((column >> 4) & 0x0F); //MSB
- LCD_CMD = column & 0x0F; //LSB
-}
-
-static void lcd_set_start_line(int line)
-{
- LCD_CMD = (line & 0x3F) | 0x40;
-}
-
-void LCD_Contrast(unsigned contrast)
-{
- int data = 0x20 + contrast * 0xC / 10;
- LCD_CMD = 0x81;
- LCD_CMD = data & 0x3F;
-}
-
-void LCD_Init()
-{
- _fsmc_init(
- 8,
- 0x10000, /*only bit 16 of addr */
- FSMC_NOE | FSMC_NWE | FSMC_NE1, /* Not connected */
- FSMC_BANK1,
- /* Normal mode, write enable, 8 bit access, SRAM, bank enabled */
- FSMC_BCR_FACCEN | FSMC_BCR_WREN | FSMC_BCR_MBKEN,
- /* Data Setup > 90ns, Address Setup = 2xHCLK to ensure no output collision in 6800
- mode since LCD E and !CS always active */
- FSMC_BTR_DATASTx(7) | FSMC_BTR_ADDHLDx(0) | FSMC_BTR_ADDSETx(2),
- 0);
-
-
-
- // LCD bias setting (11); 0xA2; 1/9
- LCD_CMD = 0xA2;
-
- // ADC selection (8) -> ADdressCounter; 0xA0; inc
- LCD_CMD = 0xA0;
-
- //Common output mode selection (15); 0xC0; normal scan
- LCD_CMD = 0xC0;
- Delay(5);
-
- //Setting built-in resistance ratio (17); 0x24; default=7.50
- LCD_CMD = 0x24;
-
- //Electronic volume control (18) -> LCD brightness; 0x20; default=32d
- LCD_CMD = 0x81;
- LCD_CMD = 0x25 & 0x3F; // = LCD_Contrast(5);
- Delay(5);
-
- //Power control setting (16); V/B, V/R, V/F are used
- LCD_CMD = 0x2F;
- Delay(5);
-
- // Read-Modify-Write (12); let read data does not increment column address
- LCD_CMD = 0xE0;
-
- lcd_set_start_line(0);
- lcd_set_page_address(0);
- lcd_set_column_address(0);
- // Display data write (6)
- lcd_display(1);
- memset(img, 0, sizeof(img));
- memset(dirty, 0, sizeof(dirty));
-}
-
-void LCD_Clear(unsigned int val)
-{
- val = (val & 0xFF) ? 0xff : 0x00;
- memset(img, val, sizeof(img));
- memset(dirty, 0xFF, sizeof(dirty));
-}
-
-void LCD_DrawStart(unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1, enum DrawDir _dir)
-{
- if (_dir == DRAW_SWNE) {
- ypos = y1; // bug fix: must do it this way to draw bmp
- dir = -1;
- } else {
- ypos = y0;
- dir = 1;
- }
- xstart = x0;
- xend = x1;
- xpos = x0;
-}
-/* Screen coordinates are as follows:
- * (128, 32) .... (0, 32)
- * ... .... ...
- * (128, 63) .... (0, 63)
- * (128, 0) .... (0, 0)
- * ... .... ...
- * (128, 31) .... (0, 31)
- */
-void LCD_DrawStop(void)
-{
- int col = 0;
- int p, c;
- for (p = 0; p < LCD_PAGES; p++) {
- int init = 0;
- for (c = 0; c < PHY_LCD_WIDTH; c++) {
- if(dirty[c] & (1 << p)) {
- if(! init) {
- lcd_set_page_address(p);
- lcd_set_column_address(c);
- } else if(col+1 != c) {
- lcd_set_column_address(c);
- }
- LCD_DATA = img[p * PHY_LCD_WIDTH + c];
- col = c;
- }
- }
- }
- memset(dirty, 0, sizeof(dirty));
-}
-
-/*
- * 2.
-Display Start Line Set
-Specifies line address (refer to Figure 6) to determine the initial display line, or COM0. The RAM
-display data becomes the top line of LCD screen. The higher number of
-lines in ascending order,
-corresponding to the duty cycle follows it. When this command changes the line address, smooth
-scrolling or a page change takes place.
-A0 (E /RD) (R/W /WR) D7 D6 D5 D4 D3 D2 D1 D0 Hex
-0 1 0 0 1 A5 A4 A3 A2 A1 A0 40h to 7Fh
-
-8.
-ADC Select
-Changes the relationship between RAM column address and segment driver. The order of
-segment driver output pads could be reversed by software. This allows flexi
-ble IC layout during
-LCD module assembly. For details, refer to the column address section of Figure 4. When display
-data is written or read, the column address is incremented by 1 as shown in Figure 4.
-A0 (E /RD) (R/W /WR) D7 D6 D5 D4 D3 D2 D1 D0 Hex Setting
- 0 1 0 1 0 1 0 0 0 0 0 A0h Normal
- 1 A1h Reverse
- */
-
-
-void LCD_DrawPixel(unsigned int color)
-{
- if (xpos < LCD_WIDTH && ypos < LCD_HEIGHT) { // both are unsigned, can not be < 0
- int y;
- int x = PHY_LCD_WIDTH - 1 - xpos; //We want to map 0 -> 128 and 128 -> 0
-
- if (ypos > 31)
- y = ypos - 32;
- else
- y = ypos + 32;
-
-
- int ycol = y / 8;
- int ybit = y & 0x07;
- if(color) {
- img[ycol * PHY_LCD_WIDTH + x] |= 1 << ybit;
- } else {
- img[ycol * PHY_LCD_WIDTH + x] &= ~(1 << ybit);
- }
- dirty[x] |= 1 << ycol;
- }
- // this must be executed to continue drawing in the next row
- xpos++;
- if (xpos > xend) {
- xpos = xstart;
- ypos += dir;
- }
-}
-
-void LCD_DrawPixelXY(unsigned int x, unsigned int y, unsigned int color)
-{
- xpos = x;
- ypos = y;
- LCD_DrawPixel(color);
-}
diff --git a/src/target/drivers/display/spi/128x64x1.c b/src/target/drivers/display/spi/128x64x1.c
new file mode 100644
index 0000000000..87679cb8ab
--- /dev/null
+++ b/src/target/drivers/display/spi/128x64x1.c
@@ -0,0 +1,57 @@
+/*
+ This project is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Deviation 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.
+
+ You should have received a copy of the GNU General Public License
+ along with Deviation. If not, see .
+*/
+#include
+#include
+#include
+#include "common.h"
+#include "gui/gui.h"
+#include "target/drivers/mcu/stm32/rcc.h"
+
+#define CS_HI() GPIO_pin_set(LCD_SPI.csn)
+#define CS_LO() GPIO_pin_clear(LCD_SPI.csn)
+#define CMD_MODE() GPIO_pin_clear(LCD_SPI_MODE)
+#define DATA_MODE() GPIO_pin_set(LCD_SPI_MODE)
+
+static void LCD_Cmd(unsigned cmd) {
+ CMD_MODE();
+ CS_LO();
+ spi_xfer(LCD_SPI.spi, cmd);
+ CS_HI();
+}
+
+static void LCD_Data(unsigned cmd) {
+ DATA_MODE();
+ CS_LO();
+ spi_xfer(LCD_SPI.spi, cmd);
+ CS_HI();
+}
+
+static void lcd_init_ports()
+{
+ // Initialization is mostly done in SPI Flash
+ // Setup CS as B.0 Data/Control = C.5
+ rcc_periph_clock_enable(get_rcc_from_pin(LCD_SPI.csn));
+ rcc_periph_clock_enable(get_rcc_from_pin(LCD_SPI_MODE));
+ GPIO_setup_output(LCD_SPI.csn, OTYPE_PUSHPULL);
+ GPIO_setup_output(LCD_SPI_MODE, OTYPE_PUSHPULL);
+ if (HAS_OLED_DISPLAY) {
+ // We >> 3 because spi_set_baudrate_prescaler takes a value of 0-7,
+ // Whereas spi_init_master uses SPI_CR1_BAUDRATE_FPCLK_DIV_xx which
+ // is pre-shifted
+ spi_set_baudrate_prescaler(LCD_SPI.spi, (OLED_SPI_RATE) >> 3);
+ }
+}
+
+#include "128x64x1_common.h"
diff --git a/src/target/drivers/display/spi/128x64x1_nt7538.c b/src/target/drivers/display/spi/128x64x1_common.h
similarity index 65%
rename from src/target/drivers/display/spi/128x64x1_nt7538.c
rename to src/target/drivers/display/spi/128x64x1_common.h
index 64078d3e96..783d2eae8e 100644
--- a/src/target/drivers/display/spi/128x64x1_nt7538.c
+++ b/src/target/drivers/display/spi/128x64x1_common.h
@@ -12,25 +12,17 @@
You should have received a copy of the GNU General Public License
along with Deviation. If not, see .
*/
-#include
-#include
-#include "common.h"
-#include "gui/gui.h"
-#include "target/drivers/mcu/stm32/rcc.h"
-#include "target/drivers/mcu/stm32/spi.h"
-
-#define CS_HI() GPIO_pin_set(LCD_SPI.csn)
-#define CS_LO() GPIO_pin_clear(LCD_SPI.csn)
-#define CMD_MODE() GPIO_pin_clear(LCD_SPI_MODE)
-#define DATA_MODE() GPIO_pin_set(LCD_SPI_MODE)
#ifndef HAS_LCD_FLIPPED
#define HAS_LCD_FLIPPED 0
#endif
-
-#ifndef LCD_CONTRAST_FUNC
- #define LCD_CONTRAST_FUNC(x) ((x) * 12 + 76) // Contrsat function for devo radios
+#ifndef HAS_LCD_SWAPPED_PAGES
+ #define HAS_LCD_SWAPPED_PAGES 0
#endif
+
+#include "128x64x1_nt7538.h"
+#include "128x64x1_oled_ssd1306.h"
+
//The screen is 129 characters, but we'll only expoise 128 of them
#define PHY_LCD_WIDTH 129
#define LCD_PAGES 8
@@ -40,20 +32,6 @@ static u16 xstart, xend; // After introducing logical view for devo10, the coor
static u16 xpos, ypos;
static s8 dir;
-void LCD_Cmd(unsigned cmd) {
- CMD_MODE();
- CS_LO();
- spi_xfer(LCD_SPI.spi, cmd);
- CS_HI();
-}
-
-void LCD_Data(unsigned cmd) {
- DATA_MODE();
- CS_LO();
- spi_xfer(LCD_SPI.spi, cmd);
- CS_HI();
-}
-
void lcd_display(uint8_t on)
{
LCD_Cmd(0xAE | (on ? 1 : 0));
@@ -79,44 +57,27 @@ void LCD_Contrast(unsigned contrast)
{
//int data = 0x20 + contrast * 0xC / 10;
LCD_Cmd(0x81);
- int c = LCD_CONTRAST_FUNC(contrast);
- LCD_Cmd(c);
+ if (HAS_OLED_DISPLAY) {
+ contrast = _oled_contrast_func(contrast);
+ } else {
+ contrast = _lcd_contrast_func(contrast);
+ }
+ LCD_Cmd(contrast);
}
void LCD_Init()
{
- //Initialization is mostly done in SPI Flash
- //Setup CS as B.0 Data/Control = C.5
-#ifndef FLASH_SPI_CFG
- _spi_init(LCD_SPI_CFG);
-#endif
- rcc_periph_clock_enable(get_rcc_from_pin(LCD_SPI.csn));
- rcc_periph_clock_enable(get_rcc_from_pin(LCD_SPI_MODE));
- GPIO_setup_output(LCD_SPI.csn, OTYPE_PUSHPULL);
- GPIO_setup_output(LCD_SPI_MODE, OTYPE_PUSHPULL);
- LCD_Cmd(0xE2); //Reset
- volatile int i = 0x8000;
- while(i) i--;
- lcd_display(0); // Display Off
- LCD_Cmd(0xA6); // Normal display
- LCD_Cmd(0xA4); // All Points Normal
- LCD_Cmd(0xA0); // Set SEG Direction (Normal)
- if (HAS_LCD_FLIPPED) {
- LCD_Cmd(0xC8); // Set COM Direction (Reversed)
- LCD_Cmd(0xA2); // Set The LCD Display Driver Voltage Bias Ratio (1/9)
+ lcd_init_ports();
+ if (HAS_OLED_DISPLAY) {
+ _oled_reset();
+ _oled_init();
} else {
- LCD_Cmd(0xEA); // ??
- LCD_Cmd(0xC4); // Common Output Mode Scan Rate
+ _lcd_reset();
+ _lcd_init();
}
- LCD_Cmd(0x2C); // Power Controller:Booster ON
- i = 0x8000;
- while(i) i--;
- LCD_Cmd(0x2E); // Power Controller: VReg ON
- i = 0x8000;
- while(i) i--;
- LCD_Cmd(0x2F); // Power Controller: VFollower ON
- i = 0x8000;
+ volatile int i = 0x8000;
while(i) i--;
+ lcd_display(0); // Display Off
lcd_set_start_line(0);
// Display data write (6)
// Clear the screen
@@ -182,13 +143,42 @@ void LCD_DrawStop(void)
memset(dirty, 0, sizeof(dirty));
}
+/*
+ * 2.
+Display Start Line Set
+Specifies line address (refer to Figure 6) to determine the initial display line, or COM0. The RAM
+display data becomes the top line of LCD screen. The higher number of
+lines in ascending order,
+corresponding to the duty cycle follows it. When this command changes the line address, smooth
+scrolling or a page change takes place.
+A0 (E /RD) (R/W /WR) D7 D6 D5 D4 D3 D2 D1 D0 Hex
+0 1 0 0 1 A5 A4 A3 A2 A1 A0 40h to 7Fh
+
+8.
+ADC Select
+Changes the relationship between RAM column address and segment driver. The order of
+segment driver output pads could be reversed by software. This allows flexi
+ble IC layout during
+LCD module assembly. For details, refer to the column address section of Figure 4. When display
+data is written or read, the column address is incremented by 1 as shown in Figure 4.
+A0 (E /RD) (R/W /WR) D7 D6 D5 D4 D3 D2 D1 D0 Hex Setting
+ 0 1 0 1 0 1 0 0 0 0 0 A0h Normal
+ 1 A1h Reverse
+ */
void LCD_DrawPixel(unsigned int color)
{
- if (xpos < LCD_WIDTH && ypos < LCD_HEIGHT) { // both are unsigned, can not be < 0
- int y = ypos;
- int x = xpos;
- int ycol = y / 8;
- int ybit = y & 0x07;
+ if (xpos < LCD_WIDTH && ypos < LCD_HEIGHT) { // both are unsigned, can not be < 0
+ int y = ypos;
+ int x = xpos;
+ if (HAS_LCD_SWAPPED_PAGES) {
+ x = PHY_LCD_WIDTH - 1 - xpos; // We want to map 0 -> 128 and 128 -> 0
+ if (ypos > 31)
+ y = ypos - 32;
+ else
+ y = ypos + 32;
+ }
+ int ycol = y / 8;
+ int ybit = y & 0x07;
if (color) {
img[ycol * PHY_LCD_WIDTH + x] |= 1 << ybit;
} else {
@@ -196,7 +186,7 @@ void LCD_DrawPixel(unsigned int color)
}
dirty[x] |= 1 << ycol;
}
- // this must be executed to continue drawing in the next row
+ // this must be executed to continue drawing in the next row
xpos++;
if (xpos > xend) {
xpos = xstart;
diff --git a/src/target/drivers/display/spi/128x64x1_nt7538.h b/src/target/drivers/display/spi/128x64x1_nt7538.h
new file mode 100644
index 0000000000..f8a4110f94
--- /dev/null
+++ b/src/target/drivers/display/spi/128x64x1_nt7538.h
@@ -0,0 +1,52 @@
+/*
+ This project is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Deviation 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.
+
+ You should have received a copy of the GNU General Public License
+ along with Deviation. If not, see .
+*/
+
+#ifndef LCD_CONTRAST_FUNC
+ #define LCD_CONTRAST_FUNC(contrast) ((contrast) * 12 + 76)
+#endif
+
+inline static unsigned _lcd_contrast_func(unsigned contrast) {
+ return LCD_CONTRAST_FUNC(contrast);
+ // Devo contrast function
+}
+
+inline static void _lcd_reset()
+{
+ LCD_Cmd(0xE2); // Reset
+}
+
+inline static void _lcd_init()
+{
+ volatile int i;
+ LCD_Cmd(0xA6); // Normal display
+ LCD_Cmd(0xA4); // All Points Normal
+ LCD_Cmd(0xA0); // Set SEG Direction (Normal)
+ if (HAS_LCD_FLIPPED) {
+ LCD_Cmd(0xC8); // Set COM Direction (Reversed)
+ LCD_Cmd(0xA2); // Set The LCD Display Driver Voltage Bias Ratio (1/9)
+ } else {
+ LCD_Cmd(0xEA); // ??
+ LCD_Cmd(0xC4); // Common Output Mode Scan Rate
+ }
+ LCD_Cmd(0x2C); // Power Controller:Booster ON
+ i = 0x8000;
+ while (i) i--;
+ LCD_Cmd(0x2E); // Power Controller: VReg ON
+ i = 0x8000;
+ while (i) i--;
+ LCD_Cmd(0x2F); // Power Controller: VFollower ON
+ i = 0x8000;
+ while (i) i--;
+}
diff --git a/src/target/drivers/display/spi/128x64x1_oled_ssd1306.c b/src/target/drivers/display/spi/128x64x1_oled_ssd1306.c
deleted file mode 100644
index d6df5a589e..0000000000
--- a/src/target/drivers/display/spi/128x64x1_oled_ssd1306.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- This project is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Deviation 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.
-
- You should have received a copy of the GNU General Public License
- along with Deviation. If not, see .
-*/
-#include
-#include
-#include
-#include "common.h"
-#include "gui/gui.h"
-#include "target/drivers/mcu/stm32/rcc.h"
-
-#define CS_HI() GPIO_pin_set(LCD_SPI.csn)
-#define CS_LO() GPIO_pin_clear(LCD_SPI.csn)
-#define CMD_MODE() GPIO_pin_clear(LCD_SPI_MODE)
-#define DATA_MODE() GPIO_pin_set(LCD_SPI_MODE)
-
-#define PHY_LCD_WIDTH 128
-#define LCD_PAGES 8
-static u8 img[PHY_LCD_WIDTH * LCD_PAGES];
-static u8 dirty[PHY_LCD_WIDTH];
-static u16 xstart, xend; // After introducing logical view for devo10, the coordinate can be >= 5000
-static u16 xpos, ypos;
-static s8 dir;
-
-void LCD_Cmd(unsigned cmd) {
- CMD_MODE();
- CS_LO();
- spi_xfer(LCD_SPI.spi, cmd);
- CS_HI();
-}
-
-void LCD_Data(unsigned cmd) {
- DATA_MODE();
- CS_LO();
- spi_xfer(LCD_SPI.spi, cmd);
- CS_HI();
-}
-
-void lcd_display(uint8_t on)
-{
- LCD_Cmd(0xAE | (on ? 1 : 0));
-}
-
-void lcd_set_page_address(uint8_t page)
-{
- LCD_Cmd(0xB0 | (page & 0x07));
-}
-
-void lcd_set_column_address(uint8_t column)
-{
- LCD_Cmd(0x10 | ((column >> 4) & 0x0F)); //MSB
- LCD_Cmd(column & 0x0F); //LSB
-}
-
-void lcd_set_start_line(int line)
-{
- LCD_Cmd((line & 0x3F) | 0x40);
-}
-
-void LCD_Contrast(unsigned contrast)
-{
- LCD_Cmd(0x81);
- int c = contrast * contrast * 255 / 100; //contrast should range from 0 to 255
- LCD_Cmd(c);
-}
-
-void LCD_Init()
-{
- //Initialization is mostly done in SPI Flash
- //Setup CS as B.0 Data/Control = C.5
- rcc_periph_clock_enable(get_rcc_from_pin(LCD_SPI.csn));
- rcc_periph_clock_enable(get_rcc_from_pin(LCD_SPI_MODE));
- GPIO_setup_output(LCD_SPI.csn, OTYPE_PUSHPULL);
- GPIO_setup_output(LCD_SPI_MODE, OTYPE_PUSHPULL);
- _msleep(100);
- lcd_display(0); //Display Off
- LCD_Cmd(0xD5); //Set Display Clock Divide Ratio / OSC Frequency
- LCD_Cmd(0x80); //Display Clock Divide Ratio / OSC Frequency
- LCD_Cmd(0xA8); //Set Multiplex Ratio
- LCD_Cmd(0x3F); //Multiplex Ratio for 128x64 (LCD_HEIGHT - 1)
- LCD_Cmd(0xD3); //Set Display Offset
- LCD_Cmd(0x00); //Display Offset (0)
- LCD_Cmd(0x40); //Set Display Start Line (0)
- LCD_Cmd(0x8D); //Set Charge Pump
- LCD_Cmd(0x10); //Charge Pump (0x10 External, 0x14 Internal DC/DC)
- LCD_Cmd(0xA1); //Set Segment Re-Map (Reversed)
- LCD_Cmd(0xC8); //Set Com Output Scan Direction (Reversed)
- LCD_Cmd(0xDA); //Set COM Hardware Configuration
- LCD_Cmd(0x12); //COM Hardware Configuration
- LCD_Cmd(0xD9); //Set Pre-Charge Period
- LCD_Cmd(0x4F); //Set Pre-Charge Period (A[7:4]:Phase 2, A[3:0]:Phase 1)
- LCD_Cmd(0xDB); //Set VCOMH Deselect Level
- LCD_Cmd(0x20); //VCOMH Deselect Level (0x00 ~ 0.65 x VCC, 0x10 ~ 0.71 x VCC, 0x20 ~ 0.77 x VCC, 0x30 ~ 0.83 x VCC)
- LCD_Cmd(0xA4); //Disable Entire Display On
- LCD_Cmd(0xA6); //Set Normal Display (not inverted)
- LCD_Cmd(0x2E); //Deactivate scroll
- //Clear the screen
- for(int page = 0; page < LCD_PAGES; page++) {
- lcd_set_page_address(page);
- lcd_set_column_address(0);
- for(int col = 0; col < PHY_LCD_WIDTH; col++)
- LCD_Data(0x00);
- }
- lcd_display(1); //Display On
- LCD_Contrast(5);
- memset(img, 0, sizeof(img));
- memset(dirty, 0, sizeof(dirty));
- _msleep(100);
-}
-
-void BACKLIGHT_Init()
-{
- rcc_periph_clock_enable(get_rcc_from_pin(BACKLIGHT_TIM.pin));
- //Turn off backlight
- GPIO_setup_input(BACKLIGHT_TIM.pin, ITYPE_FLOAT);
-}
-
-void BACKLIGHT_Brightness(unsigned brightness)
-{
- LCD_Contrast(brightness);
- if (brightness == 0) {
- lcd_display(0); //Display Off
- //Charge Pump disable
- //LCD_Cmd(0x8D); //Set Charge Pump
- //LCD_Cmd(0x10); //Charge Pump (0x10 External, 0x14 Internal DC/DC)
- } else {
- //Charge Pump enable
- //LCD_Cmd(0x8D); //Set Charge Pump
- //LCD_Cmd(0x14); //Charge Pump (0x10 External, 0x14 Internal DC/DC)
- lcd_display(1); //Display On
- }
-}
-
-void LCD_Clear(unsigned int val)
-{
- val = (val & 0xFF) ? 0xff : 0x00;
- memset(img, val, sizeof(img));
- memset(dirty, 0xFF, sizeof(dirty));
-}
-
-void LCD_DrawStart(unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1, enum DrawDir _dir)
-{
- if (_dir == DRAW_SWNE) {
- ypos = y1; // bug fix: must do it this way to draw bmp
- dir = -1;
- } else {
- ypos = y0;
- dir = 1;
- }
- xstart = x0;
- xend = x1;
- xpos = x0;
-}
-/* Screen coordinates are as follows:
- * (128, 32) .... (0, 32)
- * ... .... ...
- * (128, 63) .... (0, 63)
- * (128, 0) .... (0, 0)
- * ... .... ...
- * (128, 31) .... (0, 31)
- */
-void LCD_DrawStop(void)
-{
- int col = 0;
- int p, c;
- for (p = 0; p < LCD_PAGES; p++) {
- int init = 0;
- for (c = 0; c < PHY_LCD_WIDTH; c++) {
- if(dirty[c] & (1 << p)) {
- if(! init) {
- lcd_set_page_address(p);
- lcd_set_column_address(c);
- } else if(col+1 != c) {
- lcd_set_column_address(c);
- }
- LCD_Data(img[p * PHY_LCD_WIDTH + c]);
- col = c;
- }
- }
- }
- memset(dirty, 0, sizeof(dirty));
-}
-
-void LCD_DrawPixel(unsigned int color)
-{
- if (xpos < LCD_WIDTH && ypos < LCD_HEIGHT) { // both are unsigned, can not be < 0
- int y = ypos;
- int x = xpos;
- int ycol = y / 8;
- int ybit = y & 0x07;
- if (color) {
- img[ycol * PHY_LCD_WIDTH + x] |= 1 << ybit;
- } else {
- img[ycol * PHY_LCD_WIDTH + x] &= ~(1 << ybit);
- }
- dirty[x] |= 1 << ycol;
- }
- // this must be executed to continue drawing in the next row
- xpos++;
- if (xpos > xend) {
- xpos = xstart;
- ypos += dir;
- }
-}
-
-void LCD_DrawPixelXY(unsigned int x, unsigned int y, unsigned int color)
-{
- xpos = x;
- ypos = y;
- LCD_DrawPixel(color);
-}
diff --git a/src/target/drivers/display/spi/128x64x1_oled_ssd1306.h b/src/target/drivers/display/spi/128x64x1_oled_ssd1306.h
new file mode 100644
index 0000000000..0633617cf5
--- /dev/null
+++ b/src/target/drivers/display/spi/128x64x1_oled_ssd1306.h
@@ -0,0 +1,74 @@
+/*
+ This project is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Deviation 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.
+
+ You should have received a copy of the GNU General Public License
+ along with Deviation. If not, see .
+*/
+
+#include "target/drivers/mcu/stm32/rcc.h"
+
+void lcd_display(uint8_t on);
+
+inline static unsigned _oled_contrast_func(unsigned contrast) {
+ return contrast * contrast * 255 / 100; // contrast should range from 0 to 255
+}
+
+inline static void _oled_reset()
+{
+ // No reset for OLED
+}
+
+inline static void _oled_init()
+{
+ LCD_Cmd(0xD5); // Set Display Clock Divide Ratio / OSC Frequency
+ LCD_Cmd(0x80); // Display Clock Divide Ratio / OSC Frequency
+ LCD_Cmd(0xA8); // Set Multiplex Ratio
+ LCD_Cmd(0x3F); // Multiplex Ratio for 128x64 (LCD_HEIGHT - 1)
+ LCD_Cmd(0xD3); // Set Display Offset
+ LCD_Cmd(0x00); // Display Offset (0)
+ LCD_Cmd(0x40); // Set Display Start Line (0)
+ LCD_Cmd(0x8D); // Set Charge Pump
+ LCD_Cmd(0x10); // Charge Pump (0x10 External, 0x14 Internal DC/DC)
+ LCD_Cmd(0xA1); // Set Segment Re-Map (Reversed)
+ LCD_Cmd(0xC8); // Set Com Output Scan Direction (Reversed)
+ LCD_Cmd(0xDA); // Set COM Hardware Configuration
+ LCD_Cmd(0x12); // COM Hardware Configuration
+ LCD_Cmd(0xD9); // Set Pre-Charge Period
+ LCD_Cmd(0x4F); // Set Pre-Charge Period (A[7:4]:Phase 2, A[3:0]:Phase 1)
+ LCD_Cmd(0xDB); // Set VCOMH Deselect Level
+ LCD_Cmd(0x20); // VCOMH Deselect Level (0x00 ~ 0.65 x VCC, 0x10 ~ 0.71 x VCC, 0x20 ~ 0.77 x VCC, 0x30 ~ 0.83 x VCC)
+ LCD_Cmd(0xA4); // Disable Entire Display On
+ LCD_Cmd(0xA6); // Set Normal Display (not inverted)
+ LCD_Cmd(0x2E); // Deactivate scroll
+}
+
+/* These are called by backlight.c */
+void OLED_Backlight() {
+ rcc_periph_clock_enable(get_rcc_from_pin(BACKLIGHT_TIM.pin));
+ // Turn off backlight
+ GPIO_setup_input(BACKLIGHT_TIM.pin, ITYPE_FLOAT);
+}
+
+void OLED_Backlight_Brightness(unsigned brightness)
+{
+ LCD_Contrast(brightness);
+ if (brightness == 0) {
+ lcd_display(0); // Display Off
+ // Charge Pump disable
+ // LCD_Cmd(0x8D); // Set Charge Pump
+ // LCD_Cmd(0x10); // Charge Pump (0x10 External, 0x14 Internal DC/DC)
+ } else {
+ // Charge Pump enable
+ // LCD_Cmd(0x8D); // Set Charge Pump
+ // LCD_Cmd(0x14); // Charge Pump (0x10 External, 0x14 Internal DC/DC)
+ lcd_display(1); // Display On
+ }
+}
diff --git a/src/target/tx/devo/common/Makefile.inc b/src/target/tx/devo/common/Makefile.inc
index e2faf0b06d..3c96450887 100644
--- a/src/target/tx/devo/common/Makefile.inc
+++ b/src/target/tx/devo/common/Makefile.inc
@@ -1,6 +1,7 @@
HAS_4IN1_FLASH ?= 0
HAS_FLASH_DETECT ?= 0
USE_JTAG ?= 0
+DFU_STRING ?= "$(HGVERSION) Firmware"
ifndef BUILD_TARGET
@@ -117,7 +118,7 @@ $(LIBOPENCM3):
+$(FLOCKS) $(MAKE) -C $(SDIR)/libopencm3 TARGETS=stm32/f1 lib
$(TARGET).dfu: $(TARGET).bin
- $(SDIR)/../utils/dfu.py --name "$(HGVERSION) Firmware" $(DFU_ARGS):$< $@
+ $(SDIR)/../utils/dfu.py --name $(DFU_STRING) $(DFU_ARGS):$< $@
$(SDIR)/../utils/get_mem_usage.pl $(TARGET).map
###################################
diff --git a/src/target/tx/devo/common/common_devo.h b/src/target/tx/devo/common/common_devo.h
index 20fe43402f..d13b945620 100644
--- a/src/target/tx/devo/common/common_devo.h
+++ b/src/target/tx/devo/common/common_devo.h
@@ -40,4 +40,9 @@ static inline void LCD_ForceUpdate() {}
#ifndef HAS_PWR_SWITCH_INVERTED
#define HAS_PWR_SWITCH_INVERTED 0
#endif
+
+#ifndef HAS_OLED_DISPLAY
+ #define HAS_OLED_DISPLAY 0
+ #define TXTYPE ""
+#endif
#endif //_COMMON_DEVO_H_
diff --git a/src/target/tx/devo/common/hardware.h b/src/target/tx/devo/common/hardware.h
index 546d6b1561..2a26f176b0 100644
--- a/src/target/tx/devo/common/hardware.h
+++ b/src/target/tx/devo/common/hardware.h
@@ -49,6 +49,10 @@
})
#endif
+// This will be overridden by the OLED driver if needed
+#define LCD_SPI_RATE SPI_CR1_BR_FPCLK_DIV_4
+#define OLED_SPI_RATE SPI_CR1_BR_FPCLK_DIV_8
+
#ifndef FLASH_SPI
#define FLASH_SPI ((struct spi_csn) { \
.spi = SPI1, \
@@ -65,9 +69,7 @@
.sck = {GPIOA, GPIO5}, \
.miso = {GPIOA, GPIO6}, \
.mosi = {GPIOA, GPIO7}, \
- .rate = HAS_OLED_DISPLAY \
- ? SPI_CR1_BR_FPCLK_DIV_8 \
- : SPI_CR1_BR_FPCLK_DIV_4, \
+ .rate = LCD_SPI_RATE, \
DEFAULT_SPI_SETTINGS, \
})
#endif // SPI1_CFG
@@ -86,9 +88,7 @@
.sck = {GPIOA, GPIO5}, \
.miso = {GPIOA, GPIO6}, \
.mosi = {GPIOA, GPIO7}, \
- .rate = HAS_OLED_DISPLAY \
- ? SPI_CR1_BR_FPCLK_DIV_8 \
- : SPI_CR1_BR_FPCLK_DIV_4, \
+ .rate = LCD_SPI_RATE \
DEFAULT_SPI_SETTINGS, \
})
#endif // SPI1_CFG
diff --git a/src/target/tx/devo/devo10/Makefile.inc b/src/target/tx/devo/devo10/Makefile.inc
index c53ad3faa6..72d48651ab 100644
--- a/src/target/tx/devo/devo10/Makefile.inc
+++ b/src/target/tx/devo/devo10/Makefile.inc
@@ -1,6 +1,6 @@
FILESYSTEMS := common base_fonts 128x64x1
SCREENSIZE := 128x64x1
-DISPLAY_DRIVER := 8080/128x64x1_nt7538.c
+DISPLAY_DRIVER := 8080/128x64x1.c
DFU_ARGS := -c 10 -b 0x08004000
FONTS = filesystem/$(FILESYSTEM)/media/12normal.fon \
filesystem/$(FILESYSTEM)/media/04b03.fon
diff --git a/src/target/tx/devo/devo10/target_defs.h b/src/target/tx/devo/devo10/target_defs.h
index 9ec0e495c0..6236a43d46 100644
--- a/src/target/tx/devo/devo10/target_defs.h
+++ b/src/target/tx/devo/devo10/target_defs.h
@@ -32,6 +32,8 @@
#define DEBUG_WINDOW_SIZE 0
#endif
+#define HAS_LCD_SWAPPED_PAGES 1
+
#define MIN_BRIGHTNESS 0
#define DEFAULT_BATTERY_ALARM 8000
#define DEFAULT_BATTERY_CRITICAL 7500
diff --git a/src/target/tx/devo/devo7e-256/Makefile.inc b/src/target/tx/devo/devo7e-256/Makefile.inc
index 8b4451ea24..661da88f02 100644
--- a/src/target/tx/devo/devo7e-256/Makefile.inc
+++ b/src/target/tx/devo/devo7e-256/Makefile.inc
@@ -1,5 +1,5 @@
SCREENSIZE := 128x64x1
-DISPLAY_DRIVER := spi/128x64x1_nt7538.c
+DISPLAY_DRIVER := spi/128x64x1.c
FILESYSTEMS := common base_fonts 128x64x1
DFU_ARGS := -c 7 -b 0x08003000
FONTS = filesystem/$(FILESYSTEM)/media/12normal.fon \
diff --git a/src/target/tx/devo/devo7e/Makefile.inc b/src/target/tx/devo/devo7e/Makefile.inc
index 3f601efe46..39617d27c3 100644
--- a/src/target/tx/devo/devo7e/Makefile.inc
+++ b/src/target/tx/devo/devo7e/Makefile.inc
@@ -1,5 +1,5 @@
SCREENSIZE := 128x64x1
-DISPLAY_DRIVER := spi/128x64x1_nt7538.c
+DISPLAY_DRIVER := spi/128x64x1.c
FILESYSTEMS := common base_fonts 128x64x1
FONTS = filesystem/$(FILESYSTEM)/media/12normal.fon \
filesystem/$(FILESYSTEM)/media/04b03.fon
diff --git a/src/target/tx/devo/emu_t8sg/target_defs.h b/src/target/tx/devo/emu_t8sg/target_defs.h
index 9fe3f846ac..d44146460e 100644
--- a/src/target/tx/devo/emu_t8sg/target_defs.h
+++ b/src/target/tx/devo/emu_t8sg/target_defs.h
@@ -1,5 +1,11 @@
#include "target/drivers/mcu/emu/common_emu.h"
#include "../t8sg/target_defs.h"
+#undef HAS_OLED_DISPLAY
+char *getenv(const char *);
+static inline int _HAS_OLED_DISPLAY() {
+ return getenv("OLED") ? 1 : 0;
+}
+#define HAS_OLED_DISPLAY _HAS_OLED_DISPLAY()
#define BUTTON_MAP { 'A', 'Q', 'D', 'E', 'S', 'W', 'F', 'R', FL_Left, FL_Right, FL_Down, FL_Up, 13/*FL_Enter*/, FL_Escape, 0 }
diff --git a/src/target/tx/devo/t8sg/Makefile.inc b/src/target/tx/devo/t8sg/Makefile.inc
index 469f09d1ac..9eaa395c68 100644
--- a/src/target/tx/devo/t8sg/Makefile.inc
+++ b/src/target/tx/devo/t8sg/Makefile.inc
@@ -1,13 +1,12 @@
SCREENSIZE := 128x64x1
-DISPLAY_DRIVER := spi/128x64x1_nt7538.c
+DISPLAY_DRIVER := spi/128x64x1.c
FILESYSTEMS := common base_fonts 128x64x1
-DFU_ARGS := -c 7 -b 0x08003000
+DFU_STRING := "$(HGVERSION) Unified Firmware"
+DFU_ARGS := -c 0 -b 0x08006000
FONTS = filesystem/$(FILESYSTEM)/media/12normal.fon \
filesystem/$(FILESYSTEM)/media/04b03.fon
LANGUAGE := devo10
-OPTIMIZE_DFU := 1
-
include $(SDIR)/target/tx/devo/common/Makefile.inc
ifdef BUILD_TARGET
@@ -20,7 +19,7 @@ $(TARGET).fs_wrapper: $(LAST_MODEL)
perl -p -i -e 's/; enable-nrf24l01 = A14/ enable-nrf24l01 = A15/' filesystem/$(FILESYSTEM)/hardware.ini
perl -p -i -e 's/; has_pa-nrf24l01 = 1/ has_pa-nrf24l01 = 1/' filesystem/$(FILESYSTEM)/hardware.ini
perl -p -i -e 's/;switch_types: 3x2, 3x1, 2x2/;switch_types: 3x4, 3x3, 3x2, 3x1, 2x8, 2x7, 2x6, 2x5, 2x4, 2x3, 2x2, 2x1, potx2, potx1\n;May occur more than once if necessary.\n;Add nostock if stock FMOD and HOLD switches have been removed./' filesystem/$(FILESYSTEM)/hardware.ini
- perl -p -i -e 's/;extra-switches=/ extra-switches = nostock\n extra-switches = 3x4\n; extra-switches = 2x2\n extra-switches = potx2/' filesystem/$(FILESYSTEM)/hardware.ini
+ perl -p -i -e 's/;extra-switches=/ extra-switches = nostock\n extra-switches = 3x4\n extra-switches = 2x2\n extra-switches = potx2/' filesystem/$(FILESYSTEM)/hardware.ini
rm -f filesystem/$(FILESYSTEM)/hardware.ini.bak
endif
diff --git a/src/target/tx/devo/t8sg/channels.c b/src/target/tx/devo/t8sg/channels.c
index 80b9eca842..49ca74e6f3 100644
--- a/src/target/tx/devo/t8sg/channels.c
+++ b/src/target/tx/devo/t8sg/channels.c
@@ -10,7 +10,7 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with Deviation. If not, see .
+ along with Deviation. If not, see .
*/
#include
#include
@@ -19,7 +19,7 @@
#include "config/tx.h"
#include "../common/devo.h"
-//Duplicated in tx_buttons.c
+// Duplicated in tx_buttons.c
#define IGNORE_MASK ((1 << INP_AILERON) | (1 << INP_ELEVATOR) | (1 << INP_THROTTLE) | (1 << INP_RUDDER) | (1 << INP_NONE) | (1 << INP_LAST))
#define SWITCH_3x4 ((1 << INP_SWA0) | (1 << INP_SWA1) | (1 << INP_SWA2) \
| (1 << INP_SWB0) | (1 << INP_SWB1) | (1 << INP_SWB2) \
@@ -70,7 +70,7 @@
#define SWITCH_STOCK ((1 << INP_HOLD0) | (1 << INP_HOLD1) \
| (1 << INP_FMOD0) | (1 << INP_FMOD1))
-//Duplicated in tx_buttons.c
+// Duplicated in tx_buttons.c
enum {
SW_01 = 23,
SW_02,
@@ -93,6 +93,7 @@ void CHAN_Init()
ADC_Init();
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
+
/* configure switches for digital I/O */
gpio_set_mode(GPIOC, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN,
GPIO10 | GPIO11);
@@ -103,11 +104,11 @@ s32 CHAN_ReadRawInput(int channel)
{
s32 value = 0;
if ((~Transmitter.ignore_src & SWITCH_STOCK) == SWITCH_STOCK) {
- switch(channel) {
+ switch (channel) {
case INP_HOLD0: value = gpio_get(GPIOC, GPIO11); break;
- case INP_HOLD1: value = ! gpio_get(GPIOC, GPIO11); break;
+ case INP_HOLD1: value = !gpio_get(GPIOC, GPIO11); break;
case INP_FMOD0: value = gpio_get(GPIOC, GPIO10); break;
- case INP_FMOD1: value = ! gpio_get(GPIOC, GPIO10); break;
+ case INP_FMOD1: value = !gpio_get(GPIOC, GPIO10); break;
case INP_SWA0: value = global_extra_switches & 0x04; break;
case INP_SWA1: value = !(global_extra_switches & 0x0c); break;
case INP_SWA2: value = global_extra_switches & 0x08; break;
@@ -121,89 +122,89 @@ s32 CHAN_ReadRawInput(int channel)
}
} else {
if ((~Transmitter.ignore_src & SWITCH_3x1) == SWITCH_3x1) {
- switch(channel) {
+ switch (channel) {
case INP_SWA0: value = (global_extra_switches & (1 << (SW_02 - 1))); break;
case INP_SWA1: value = (!(global_extra_switches & (1 << (SW_01 - 1))) && !(global_extra_switches & (1 << (SW_02 - 1)))); break;
case INP_SWA2: value = (global_extra_switches & (1 << (SW_01 - 1))); break;
}
} else if ((~Transmitter.ignore_src & SWITCH_2x8) == SWITCH_2x8) {
- switch(channel) {
+ switch (channel) {
case INP_SWA0: value = !(global_extra_switches & (1 << (SW_03 - 1))); break;
case INP_SWA1: value = (global_extra_switches & (1 << (SW_03 - 1))); break;
}
}
if ((~Transmitter.ignore_src & SWITCH_3x2) == SWITCH_3x2) {
- switch(channel) {
+ switch (channel) {
case INP_SWB0: value = (global_extra_switches & (1 << (SW_04 - 1))); break;
case INP_SWB1: value = (!(global_extra_switches & (1 << (SW_03 - 1))) && !(global_extra_switches & (1 << (SW_04 - 1)))); break;
case INP_SWB2: value = (global_extra_switches & (1 << (SW_03 - 1))); break;
}
} else if ((~Transmitter.ignore_src & SWITCH_2x7) == SWITCH_2x7) {
- switch(channel) {
+ switch (channel) {
case INP_SWB0: value = !(global_extra_switches & (1 << (SW_04 - 1))); break;
case INP_SWB1: value = (global_extra_switches & (1 << (SW_04 - 1))); break;
}
}
if ((~Transmitter.ignore_src & SWITCH_3x3) == SWITCH_3x3) {
- switch(channel) {
+ switch (channel) {
case INP_SWC0: value = (global_extra_switches & (1 << (SW_06 - 1))); break;
case INP_SWC1: value = (!(global_extra_switches & (1 << (SW_05 - 1))) && !(global_extra_switches & (1 << (SW_06 - 1)))); break;
case INP_SWC2: value = (global_extra_switches & (1 << (SW_05 - 1))); break;
}
} else if ((~Transmitter.ignore_src & SWITCH_2x6) == SWITCH_2x6) {
- switch(channel) {
+ switch (channel) {
case INP_SWC0: value = !(global_extra_switches & (1 << (SW_05 - 1))); break;
case INP_SWC1: value = (global_extra_switches & (1 << (SW_05 - 1))); break;
}
}
if ((~Transmitter.ignore_src & SWITCH_3x4) == SWITCH_3x4) {
- switch(channel) {
+ switch (channel) {
case INP_SWD0: value = (global_extra_switches & (1 << (SW_08 - 1))); break;
case INP_SWD1: value = (!(global_extra_switches & (1 << (SW_07 - 1))) && !(global_extra_switches & (1 << (SW_08 - 1)))); break;
case INP_SWD2: value = (global_extra_switches & (1 << (SW_07 - 1))); break;
}
} else if ((~Transmitter.ignore_src & SWITCH_2x5) == SWITCH_2x5) {
- switch(channel) {
+ switch (channel) {
case INP_SWD0: value = !(global_extra_switches & (1 << (SW_06 - 1))); break;
case INP_SWD1: value = (global_extra_switches & (1 << (SW_06 - 1))); break;
}
}
if ((~Transmitter.ignore_src & SWITCH_2x4) == SWITCH_2x4) {
- switch(channel) {
+ switch (channel) {
case INP_SWE0: value = !(global_extra_switches & (1 << (SW_07 - 1))); break;
case INP_SWE1: value = (global_extra_switches & (1 << (SW_07 - 1))); break;
}
}
if ((~Transmitter.ignore_src & SWITCH_2x3) == SWITCH_2x3) {
- switch(channel) {
+ switch (channel) {
case INP_SWF0: value = !(global_extra_switches & (1 << (SW_08 - 1))); break;
case INP_SWF1: value = (global_extra_switches & (1 << (SW_08 - 1))); break;
}
}
if ((~Transmitter.ignore_src & SWITCH_2x2) == SWITCH_2x2) {
- switch(channel) {
+ switch (channel) {
case INP_SWG0: value = !(global_extra_switches & (1 << (SW_09 - 1))); break;
case INP_SWG1: value = (global_extra_switches & (1 << (SW_09 - 1))); break;
}
}
if ((~Transmitter.ignore_src & SWITCH_2x1) == SWITCH_2x1) {
- switch(channel) {
+ switch (channel) {
case INP_SWH0: value = !(global_extra_switches & (1 << (SW_10 - 1))); break;
case INP_SWH1: value = (global_extra_switches & (1 << (SW_10 - 1))); break;
}
}
}
if ((~Transmitter.ignore_src & POT_1) == POT_1) {
- switch(channel) {
+ switch (channel) {
case INP_AUX4: value = adc_array_raw[4]; break;
}
}
if ((~Transmitter.ignore_src & POT_2) == POT_2) {
- switch(channel) {
+ switch (channel) {
case INP_AUX5: value = adc_array_raw[5]; break;
}
}
- switch(channel) {
+ switch (channel) {
case INP_THROTTLE: value = adc_array_raw[0]; break; // bug fix: right vertical
case INP_AILERON: value = adc_array_raw[1]; break; // bug fix: right horizon
case INP_RUDDER: value = adc_array_raw[2]; break; // bug fix: left horizon
@@ -214,23 +215,23 @@ s32 CHAN_ReadRawInput(int channel)
s32 CHAN_ReadInput(int channel)
{
s32 value = CHAN_ReadRawInput(channel);
- if(channel <= INP_HAS_CALIBRATION) {
+ if (channel <= INP_HAS_CALIBRATION) {
s32 max = Transmitter.calibration[channel - 1].max;
s32 min = Transmitter.calibration[channel - 1].min;
s32 zero = Transmitter.calibration[channel - 1].zero;
- if(! zero) {
- //If this input doesn't have a zero, calculate from max/min
+ if (!zero) {
+ // If this input doesn't have a zero, calculate from max/min
zero = ((u32)max + min) / 2;
}
// Derate min and max by 1% to ensure we can get all the way to 100%
max = (max - zero) * 99 / 100;
min = (min - zero) * 99 / 100;
- if(value >= zero) {
+ if (value >= zero) {
value = (value - zero) * CHAN_MAX_VALUE / max;
} else {
value = (value - zero) * CHAN_MIN_VALUE / min;
}
- //Bound output
+ // Bound output
if (value > CHAN_MAX_VALUE)
value = CHAN_MAX_VALUE;
if (value < CHAN_MIN_VALUE)
@@ -238,42 +239,42 @@ s32 CHAN_ReadInput(int channel)
} else {
value = value ? CHAN_MAX_VALUE : CHAN_MIN_VALUE;
}
- if (channel == INP_THROTTLE || channel == INP_AILERON || channel == INP_AUX4 || channel == INP_AUX5)
+ if (channel == INP_THROTTLE || channel == INP_AILERON || channel == INP_AUX4)
value = -value;
return value;
}
void CHAN_SetSwitchCfg(const char *str)
{
- if(strcmp(str, "3x4") == 0) {
+ if (strcmp(str, "3x4") == 0) {
Transmitter.ignore_src &= ~SWITCH_3x4;
- } else if(strcmp(str, "3x3") == 0) {
+ } else if (strcmp(str, "3x3") == 0) {
Transmitter.ignore_src &= ~SWITCH_3x3;
- } else if(strcmp(str, "3x2") == 0) {
+ } else if (strcmp(str, "3x2") == 0) {
Transmitter.ignore_src &= ~SWITCH_3x2;
- } else if(strcmp(str, "3x1") == 0) {
+ } else if (strcmp(str, "3x1") == 0) {
Transmitter.ignore_src &= ~SWITCH_3x1;
- } else if(strcmp(str, "2x8") == 0) {
+ } else if (strcmp(str, "2x8") == 0) {
Transmitter.ignore_src &= ~SWITCH_2x8;
- } else if(strcmp(str, "2x7") == 0) {
+ } else if (strcmp(str, "2x7") == 0) {
Transmitter.ignore_src &= ~SWITCH_2x7;
- } else if(strcmp(str, "2x6") == 0) {
+ } else if (strcmp(str, "2x6") == 0) {
Transmitter.ignore_src &= ~SWITCH_2x6;
- } else if(strcmp(str, "2x5") == 0) {
+ } else if (strcmp(str, "2x5") == 0) {
Transmitter.ignore_src &= ~SWITCH_2x5;
- } else if(strcmp(str, "2x4") == 0) {
+ } else if (strcmp(str, "2x4") == 0) {
Transmitter.ignore_src &= ~SWITCH_2x4;
- } else if(strcmp(str, "2x3") == 0) {
+ } else if (strcmp(str, "2x3") == 0) {
Transmitter.ignore_src &= ~SWITCH_2x3;
- } else if(strcmp(str, "2x2") == 0) {
+ } else if (strcmp(str, "2x2") == 0) {
Transmitter.ignore_src &= ~SWITCH_2x2;
- } else if(strcmp(str, "2x1") == 0) {
+ } else if (strcmp(str, "2x1") == 0) {
Transmitter.ignore_src &= ~SWITCH_2x1;
- } else if(strcmp(str, "potx2") == 0) {
+ } else if (strcmp(str, "potx2") == 0) {
Transmitter.ignore_src &= ~POT_2;
- } else if(strcmp(str, "potx1") == 0) {
+ } else if (strcmp(str, "potx1") == 0) {
Transmitter.ignore_src &= ~POT_1;
- } else if(strcmp(str, "nostock") == 0) {
+ } else if (strcmp(str, "nostock") == 0) {
Transmitter.ignore_src |= SWITCH_STOCK;
} else {
Transmitter.ignore_src = ~IGNORE_MASK & ~SWITCH_STOCK;
diff --git a/src/target/tx/devo/t8sg/hardware.h b/src/target/tx/devo/t8sg/hardware.h
index 9afd7ab08e..98243bceec 100644
--- a/src/target/tx/devo/t8sg/hardware.h
+++ b/src/target/tx/devo/t8sg/hardware.h
@@ -26,4 +26,5 @@
ADC_CHAN(GPIOC, GPIO4), /* ADC12_14 */ \
}
#endif // HAS_EXTRA_POTS
+
#endif // _DEVO7E256_HARDWARE_H_
diff --git a/src/target/tx/devo/t8sg/t8sg.common.ld b/src/target/tx/devo/t8sg/t8sg.common.ld
new file mode 100644
index 0000000000..b2b50e48af
--- /dev/null
+++ b/src/target/tx/devo/t8sg/t8sg.common.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ } >rom
+ .rodata :{
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ } >rom
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/src/target/tx/devo/t8sg/t8sg.ld b/src/target/tx/devo/t8sg/t8sg.ld
index b15aa4df03..b9b26da64d 100644
--- a/src/target/tx/devo/t8sg/t8sg.ld
+++ b/src/target/tx/devo/t8sg/t8sg.ld
@@ -1,8 +1,7 @@
MEMORY
{
/* Devo7e-256 has 256K, and bootloader takes up 12K */
- rom (rx) : ORIGIN = 0x08003000, LENGTH = 244K
+ rom (rx) : ORIGIN = 0x08006000, LENGTH = 232K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K
}
-_crc_offset = 0x2000; /* CRC is located at 0x08005000 */
-INCLUDE target/tx/devo/common/devo.ld
+INCLUDE target/tx/devo/t8sg/t8sg.common.ld
diff --git a/src/target/tx/devo/t8sg/target_defs.h b/src/target/tx/devo/t8sg/target_defs.h
index 2ebda82797..e81d01349a 100644
--- a/src/target/tx/devo/t8sg/target_defs.h
+++ b/src/target/tx/devo/t8sg/target_defs.h
@@ -1,13 +1,10 @@
-#ifndef _T8SG_TARGET_H_
-#define _T8SG_TARGET_H_
+#ifndef _T8SG_V2_PLUS_TARGET_H_
+#define _T8SG_V2_PLUS_TARGET_H_
-#define TXID 0x18
-#define VECTOR_TABLE_LOCATION 0x3000
+#define TXID 0x7e
+#define VECTOR_TABLE_LOCATION 0x6000
+#define HAS_FLASH_DETECT 1
#define SPIFLASH_SECTOR_OFFSET 0
-#define SPIFLASH_SECTORS 512
-
-#define HAS_LCD_FLIPPED 1
-#define LCD_CONTRAST_FUNC(x) (x)
#define HAS_STANDARD_GUI 1
#define HAS_ADVANCED_GUI 1
@@ -31,6 +28,16 @@
#define HAS_AUDIO_UART 1
#define HAS_MUSIC_CONFIG 1
+// TXTYPE points at a memory address inside the bootloader that
+// contains the tx model name. Only Transmitters using deviation-bootloader
+// will have this string. It is always located right after the jump table,
+// And is 12 bytes long. Current valid values are:
+// T8SGV1, T8SGV2, T8SGV2+, T8SGV3, T8SGV3+
+#define TXTYPE ((char *)(0x08000000 + VECTOR_TABLE_LOCATION - 0x3000 + 0x400))
+#define HAS_OLED_DISPLAY (TXTYPE[6] == '+')
+#define LCD_CONTRAST_FUNC(x) (x)
+#define HAS_LCD_FLIPPED 1
+
#ifdef BUILDTYPE_DEV
#define DEBUG_WINDOW_SIZE 200
#else
@@ -38,8 +45,8 @@
#endif
#define MIN_BRIGHTNESS 0
-#define DEFAULT_BATTERY_ALARM 7400
-#define DEFAULT_BATTERY_CRITICAL 7100
+#define DEFAULT_BATTERY_ALARM 4100
+#define DEFAULT_BATTERY_CRITICAL 3900
#define MAX_BATTERY_ALARM 12000
#define MIN_BATTERY_ALARM 3300
#define MAX_POWER_ALARM 60
@@ -64,4 +71,4 @@
#include "hardware.h"
#include "../common/common_devo.h"
-#endif //_T8SG_TARGET_H_
+#endif // _T8SG_V2_PLUS_TARGET_H_
diff --git a/src/target/tx/devo/t8sg_v1/Makefile.inc b/src/target/tx/devo/t8sg_v1/Makefile.inc
new file mode 100644
index 0000000000..0dc9bf5801
--- /dev/null
+++ b/src/target/tx/devo/t8sg_v1/Makefile.inc
@@ -0,0 +1,26 @@
+SCREENSIZE := 128x64x1
+DISPLAY_DRIVER := spi/128x64x1.c
+FILESYSTEMS := common base_fonts 128x64x1
+DFU_ARGS := -c 7 -b 0x08003000
+FONTS = filesystem/$(FILESYSTEM)/media/12normal.fon \
+ filesystem/$(FILESYSTEM)/media/04b03.fon
+LANGUAGE := devo10
+
+OPTIMIZE_DFU := 1
+
+include $(SDIR)/target/tx/devo/common/Makefile.inc
+
+ifdef BUILD_TARGET
+
+$(TARGET).fs_wrapper: $(LAST_MODEL)
+ perl -p -i -e 's/; enable-a7105 = A13/ enable-a7105 = A13/' filesystem/$(FILESYSTEM)/hardware.ini
+ perl -p -i -e 's/; has_pa-a7105 = 1/ has_pa-a7105 = 1/' filesystem/$(FILESYSTEM)/hardware.ini
+ perl -p -i -e 's/; enable-cc2500 = A14/ enable-cc2500 = A14/' filesystem/$(FILESYSTEM)/hardware.ini
+ perl -p -i -e 's/; has_pa-cc2500 = 1/ has_pa-cc2500 = 1/' filesystem/$(FILESYSTEM)/hardware.ini
+ perl -p -i -e 's/; enable-nrf24l01 = A14/ enable-nrf24l01 = A15/' filesystem/$(FILESYSTEM)/hardware.ini
+ perl -p -i -e 's/; has_pa-nrf24l01 = 1/ has_pa-nrf24l01 = 1/' filesystem/$(FILESYSTEM)/hardware.ini
+ perl -p -i -e 's/;switch_types: 3x2, 3x1, 2x2/;switch_types: 3x4, 3x3, 3x2, 3x1, 2x8, 2x7, 2x6, 2x5, 2x4, 2x3, 2x2, 2x1, potx2, potx1\n;May occur more than once if necessary.\n;Add nostock if stock FMOD and HOLD switches have been removed./' filesystem/$(FILESYSTEM)/hardware.ini
+ perl -p -i -e 's/;extra-switches=/ extra-switches = nostock\n extra-switches = 3x4\n; extra-switches = 2x2\n extra-switches = potx2/' filesystem/$(FILESYSTEM)/hardware.ini
+ rm -f filesystem/$(FILESYSTEM)/hardware.ini.bak
+
+endif
diff --git a/src/target/tx/devo/t8sg_v1/capabilities.h b/src/target/tx/devo/t8sg_v1/capabilities.h
new file mode 100644
index 0000000000..3a7a95ae48
--- /dev/null
+++ b/src/target/tx/devo/t8sg_v1/capabilities.h
@@ -0,0 +1,92 @@
+#ifdef CHANDEF
+ CHANDEF(AILERON)
+ CHANDEF(ELEVATOR)
+ CHANDEF(THROTTLE)
+ CHANDEF(RUDDER)
+ CHANDEF(AUX4)
+ CHANDEF(AUX5)
+ CHANDEF(HOLD0)
+ CHANDEF(HOLD1)
+ CHANDEF(FMOD0)
+ CHANDEF(FMOD1)
+ CHANDEF(SWA0)
+ CHANDEF(SWA1)
+ CHANDEF(SWA2)
+ CHANDEF(SWB0)
+ CHANDEF(SWB1)
+ CHANDEF(SWB2)
+ CHANDEF(SWC0)
+ CHANDEF(SWC1)
+ CHANDEF(SWC2)
+ CHANDEF(SWD0)
+ CHANDEF(SWD1)
+ CHANDEF(SWD2)
+ CHANDEF(SWE0)
+ CHANDEF(SWE1)
+ CHANDEF(SWF0)
+ CHANDEF(SWF1)
+ CHANDEF(SWG0)
+ CHANDEF(SWG1)
+ CHANDEF(SWH0)
+ CHANDEF(SWH1)
+#endif
+
+#ifdef UNDEF_INP
+#define INP_RUD_DR0 INP_SWD0
+#define INP_RUD_DR1 INP_SWD1
+#define INP_ELE_DR0 INP_SWD0
+#define INP_ELE_DR1 INP_SWD1
+#define INP_AIL_DR0 INP_SWD0
+#define INP_AIL_DR1 INP_SWD1
+#define INP_FMOD2 INP_SWA2
+#define INP_MIX0 INP_SWC0
+#define INP_MIX1 INP_SWC1
+#define INP_MIX2 INP_SWC2
+#define INP_GEAR0 INP_SWB0
+#define INP_GEAR1 INP_SWB1
+#endif
+
+#ifdef CHANMAP
+// These are legacy mappings
+ CHANMAP("DR", SWD1)
+ CHANMAP("RUD DR", SWD1)
+ CHANMAP("ELE_DR", SWD1)
+ CHANMAP("AIL_DR", SWD1)
+ CHANMAP("GEAR", SWB1)
+// Current mappings
+ CHANMAP("DR0", SWD0)
+ CHANMAP("DR1", SWD1)
+ CHANMAP("RUD DR0", SWD0)
+ CHANMAP("RUD DR1", SWD1)
+ CHANMAP("ELE DR0", SWD0)
+ CHANMAP("ELE DR1", SWD1)
+ CHANMAP("AIL DR0", SWD0)
+ CHANMAP("AIL DR1", SWD1)
+ CHANMAP("HOLD0", SWD0)
+ CHANMAP("HOLD1", SWD1)
+ CHANMAP("FMODE0", SWA0)
+ CHANMAP("FMODE1", SWA1)
+ CHANMAP("FMODE2", SWA2)
+ CHANMAP("MIX0", SWC0)
+ CHANMAP("MIX1", SWC1)
+ CHANMAP("MIX2", SWC2)
+ CHANMAP("GEAR0", SWB0)
+ CHANMAP("GEAR1", SWB1)
+#endif
+
+#ifdef BUTTONDEF
+ BUTTONDEF(TRIM_LV_NEG) /* LEFT-VERTICAL */
+ BUTTONDEF(TRIM_LV_POS)
+ BUTTONDEF(TRIM_RV_NEG) /* RIGHT-VERTICAL */
+ BUTTONDEF(TRIM_RV_POS)
+ BUTTONDEF(TRIM_LH_NEG) /* LEFT-HORIZONTAL */
+ BUTTONDEF(TRIM_LH_POS)
+ BUTTONDEF(TRIM_RH_NEG) /* RIGHT-HORIZONTAL */
+ BUTTONDEF(TRIM_RH_POS)
+ BUTTONDEF(LEFT)
+ BUTTONDEF(RIGHT)
+ BUTTONDEF(DOWN)
+ BUTTONDEF(UP)
+ BUTTONDEF(ENTER)
+ BUTTONDEF(EXIT)
+#endif
diff --git a/src/target/tx/devo/t8sg_v1/channels.c b/src/target/tx/devo/t8sg_v1/channels.c
new file mode 100644
index 0000000000..49ca74e6f3
--- /dev/null
+++ b/src/target/tx/devo/t8sg_v1/channels.c
@@ -0,0 +1,282 @@
+/*
+ This project is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Deviation 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.
+
+ You should have received a copy of the GNU General Public License
+ along with Deviation. If not, see .
+*/
+#include
+#include
+#include "common.h"
+#include "mixer.h"
+#include "config/tx.h"
+#include "../common/devo.h"
+
+// Duplicated in tx_buttons.c
+#define IGNORE_MASK ((1 << INP_AILERON) | (1 << INP_ELEVATOR) | (1 << INP_THROTTLE) | (1 << INP_RUDDER) | (1 << INP_NONE) | (1 << INP_LAST))
+#define SWITCH_3x4 ((1 << INP_SWA0) | (1 << INP_SWA1) | (1 << INP_SWA2) \
+ | (1 << INP_SWB0) | (1 << INP_SWB1) | (1 << INP_SWB2) \
+ | (1 << INP_SWC0) | (1 << INP_SWC1) | (1 << INP_SWC2) \
+ | (1 << INP_SWD0) | (1 << INP_SWD1) | (1 << INP_SWD2))
+#define SWITCH_3x3 ((1 << INP_SWA0) | (1 << INP_SWA1) | (1 << INP_SWA2) \
+ | (1 << INP_SWB0) | (1 << INP_SWB1) | (1 << INP_SWB2) \
+ | (1 << INP_SWC0) | (1 << INP_SWC1) | (1 << INP_SWC2))
+#define SWITCH_3x2 ((1 << INP_SWA0) | (1 << INP_SWA1) | (1 << INP_SWA2) \
+ | (1 << INP_SWB0) | (1 << INP_SWB1) | (1 << INP_SWB2))
+#define SWITCH_3x1 ((1 << INP_SWA0) | (1 << INP_SWA1) | (1 << INP_SWA2))
+#define SWITCH_2x8 ((1 << INP_SWH0) | (1 << INP_SWH1) \
+ | (1 << INP_SWG0) | (1 << INP_SWG1) \
+ | (1 << INP_SWF0) | (1 << INP_SWF1) \
+ | (1 << INP_SWE0) | (1 << INP_SWE1) \
+ | (1 << INP_SWD0) | (1 << INP_SWD1) \
+ | (1 << INP_SWC0) | (1 << INP_SWC1) \
+ | (1 << INP_SWB0) | (1 << INP_SWB1) \
+ | (1 << INP_SWA0) | (1 << INP_SWA1))
+#define SWITCH_2x7 ((1 << INP_SWH0) | (1 << INP_SWH1) \
+ | (1 << INP_SWG0) | (1 << INP_SWG1) \
+ | (1 << INP_SWF0) | (1 << INP_SWF1) \
+ | (1 << INP_SWE0) | (1 << INP_SWE1) \
+ | (1 << INP_SWD0) | (1 << INP_SWD1) \
+ | (1 << INP_SWC0) | (1 << INP_SWC1) \
+ | (1 << INP_SWB0) | (1 << INP_SWB1))
+#define SWITCH_2x6 ((1 << INP_SWH0) | (1 << INP_SWH1) \
+ | (1 << INP_SWG0) | (1 << INP_SWG1) \
+ | (1 << INP_SWF0) | (1 << INP_SWF1) \
+ | (1 << INP_SWE0) | (1 << INP_SWE1) \
+ | (1 << INP_SWD0) | (1 << INP_SWD1) \
+ | (1 << INP_SWC0) | (1 << INP_SWC1))
+#define SWITCH_2x5 ((1 << INP_SWH0) | (1 << INP_SWH1) \
+ | (1 << INP_SWG0) | (1 << INP_SWG1) \
+ | (1 << INP_SWF0) | (1 << INP_SWF1) \
+ | (1 << INP_SWE0) | (1 << INP_SWE1) \
+ | (1 << INP_SWD0) | (1 << INP_SWD1))
+#define SWITCH_2x4 ((1 << INP_SWH0) | (1 << INP_SWH1) \
+ | (1 << INP_SWG0) | (1 << INP_SWG1) \
+ | (1 << INP_SWF0) | (1 << INP_SWF1) \
+ | (1 << INP_SWE0) | (1 << INP_SWE1))
+#define SWITCH_2x3 ((1 << INP_SWH0) | (1 << INP_SWH1) \
+ | (1 << INP_SWG0) | (1 << INP_SWG1) \
+ | (1 << INP_SWF0) | (1 << INP_SWF1))
+#define SWITCH_2x2 ((1 << INP_SWH0) | (1 << INP_SWH1) \
+ | (1 << INP_SWG0) | (1 << INP_SWG1))
+#define SWITCH_2x1 ((1 << INP_SWH0) | (1 << INP_SWH1))
+#define SWITCH_STOCK ((1 << INP_HOLD0) | (1 << INP_HOLD1) \
+ | (1 << INP_FMOD0) | (1 << INP_FMOD1))
+
+// Duplicated in tx_buttons.c
+enum {
+ SW_01 = 23,
+ SW_02,
+ SW_03,
+ SW_04,
+ SW_05,
+ SW_06,
+ SW_07,
+ SW_08,
+ SW_09,
+ SW_10
+};
+
+#define POT_2 ((1 << INP_AUX4) | (1 << INP_AUX5))
+#define POT_1 (1 << INP_AUX4)
+
+extern u32 global_extra_switches;
+void CHAN_Init()
+{
+ ADC_Init();
+
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
+
+ /* configure switches for digital I/O */
+ gpio_set_mode(GPIOC, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN,
+ GPIO10 | GPIO11);
+ gpio_set(GPIOC, GPIO10 | GPIO11);
+}
+
+s32 CHAN_ReadRawInput(int channel)
+{
+ s32 value = 0;
+ if ((~Transmitter.ignore_src & SWITCH_STOCK) == SWITCH_STOCK) {
+ switch (channel) {
+ case INP_HOLD0: value = gpio_get(GPIOC, GPIO11); break;
+ case INP_HOLD1: value = !gpio_get(GPIOC, GPIO11); break;
+ case INP_FMOD0: value = gpio_get(GPIOC, GPIO10); break;
+ case INP_FMOD1: value = !gpio_get(GPIOC, GPIO10); break;
+ case INP_SWA0: value = global_extra_switches & 0x04; break;
+ case INP_SWA1: value = !(global_extra_switches & 0x0c); break;
+ case INP_SWA2: value = global_extra_switches & 0x08; break;
+ case INP_SWB0: value = global_extra_switches & 0x01; break;
+ case INP_SWB1: value = !(global_extra_switches & 0x03); break;
+ case INP_SWB2: value = global_extra_switches & 0x02; break;
+ case INP_SWG0: value = global_extra_switches & 0x04; break;
+ case INP_SWG1: value = !(global_extra_switches & 0x0c); break;
+ case INP_SWH0: value = global_extra_switches & 0x01; break;
+ case INP_SWH1: value = !(global_extra_switches & 0x03); break;
+ }
+ } else {
+ if ((~Transmitter.ignore_src & SWITCH_3x1) == SWITCH_3x1) {
+ switch (channel) {
+ case INP_SWA0: value = (global_extra_switches & (1 << (SW_02 - 1))); break;
+ case INP_SWA1: value = (!(global_extra_switches & (1 << (SW_01 - 1))) && !(global_extra_switches & (1 << (SW_02 - 1)))); break;
+ case INP_SWA2: value = (global_extra_switches & (1 << (SW_01 - 1))); break;
+ }
+ } else if ((~Transmitter.ignore_src & SWITCH_2x8) == SWITCH_2x8) {
+ switch (channel) {
+ case INP_SWA0: value = !(global_extra_switches & (1 << (SW_03 - 1))); break;
+ case INP_SWA1: value = (global_extra_switches & (1 << (SW_03 - 1))); break;
+ }
+ }
+ if ((~Transmitter.ignore_src & SWITCH_3x2) == SWITCH_3x2) {
+ switch (channel) {
+ case INP_SWB0: value = (global_extra_switches & (1 << (SW_04 - 1))); break;
+ case INP_SWB1: value = (!(global_extra_switches & (1 << (SW_03 - 1))) && !(global_extra_switches & (1 << (SW_04 - 1)))); break;
+ case INP_SWB2: value = (global_extra_switches & (1 << (SW_03 - 1))); break;
+ }
+ } else if ((~Transmitter.ignore_src & SWITCH_2x7) == SWITCH_2x7) {
+ switch (channel) {
+ case INP_SWB0: value = !(global_extra_switches & (1 << (SW_04 - 1))); break;
+ case INP_SWB1: value = (global_extra_switches & (1 << (SW_04 - 1))); break;
+ }
+ }
+ if ((~Transmitter.ignore_src & SWITCH_3x3) == SWITCH_3x3) {
+ switch (channel) {
+ case INP_SWC0: value = (global_extra_switches & (1 << (SW_06 - 1))); break;
+ case INP_SWC1: value = (!(global_extra_switches & (1 << (SW_05 - 1))) && !(global_extra_switches & (1 << (SW_06 - 1)))); break;
+ case INP_SWC2: value = (global_extra_switches & (1 << (SW_05 - 1))); break;
+ }
+ } else if ((~Transmitter.ignore_src & SWITCH_2x6) == SWITCH_2x6) {
+ switch (channel) {
+ case INP_SWC0: value = !(global_extra_switches & (1 << (SW_05 - 1))); break;
+ case INP_SWC1: value = (global_extra_switches & (1 << (SW_05 - 1))); break;
+ }
+ }
+ if ((~Transmitter.ignore_src & SWITCH_3x4) == SWITCH_3x4) {
+ switch (channel) {
+ case INP_SWD0: value = (global_extra_switches & (1 << (SW_08 - 1))); break;
+ case INP_SWD1: value = (!(global_extra_switches & (1 << (SW_07 - 1))) && !(global_extra_switches & (1 << (SW_08 - 1)))); break;
+ case INP_SWD2: value = (global_extra_switches & (1 << (SW_07 - 1))); break;
+ }
+ } else if ((~Transmitter.ignore_src & SWITCH_2x5) == SWITCH_2x5) {
+ switch (channel) {
+ case INP_SWD0: value = !(global_extra_switches & (1 << (SW_06 - 1))); break;
+ case INP_SWD1: value = (global_extra_switches & (1 << (SW_06 - 1))); break;
+ }
+ }
+ if ((~Transmitter.ignore_src & SWITCH_2x4) == SWITCH_2x4) {
+ switch (channel) {
+ case INP_SWE0: value = !(global_extra_switches & (1 << (SW_07 - 1))); break;
+ case INP_SWE1: value = (global_extra_switches & (1 << (SW_07 - 1))); break;
+ }
+ }
+ if ((~Transmitter.ignore_src & SWITCH_2x3) == SWITCH_2x3) {
+ switch (channel) {
+ case INP_SWF0: value = !(global_extra_switches & (1 << (SW_08 - 1))); break;
+ case INP_SWF1: value = (global_extra_switches & (1 << (SW_08 - 1))); break;
+ }
+ }
+ if ((~Transmitter.ignore_src & SWITCH_2x2) == SWITCH_2x2) {
+ switch (channel) {
+ case INP_SWG0: value = !(global_extra_switches & (1 << (SW_09 - 1))); break;
+ case INP_SWG1: value = (global_extra_switches & (1 << (SW_09 - 1))); break;
+ }
+ }
+ if ((~Transmitter.ignore_src & SWITCH_2x1) == SWITCH_2x1) {
+ switch (channel) {
+ case INP_SWH0: value = !(global_extra_switches & (1 << (SW_10 - 1))); break;
+ case INP_SWH1: value = (global_extra_switches & (1 << (SW_10 - 1))); break;
+ }
+ }
+ }
+ if ((~Transmitter.ignore_src & POT_1) == POT_1) {
+ switch (channel) {
+ case INP_AUX4: value = adc_array_raw[4]; break;
+ }
+ }
+ if ((~Transmitter.ignore_src & POT_2) == POT_2) {
+ switch (channel) {
+ case INP_AUX5: value = adc_array_raw[5]; break;
+ }
+ }
+ switch (channel) {
+ case INP_THROTTLE: value = adc_array_raw[0]; break; // bug fix: right vertical
+ case INP_AILERON: value = adc_array_raw[1]; break; // bug fix: right horizon
+ case INP_RUDDER: value = adc_array_raw[2]; break; // bug fix: left horizon
+ case INP_ELEVATOR: value = adc_array_raw[3]; break; // bug fix: left vertical
+ }
+ return value;
+}
+s32 CHAN_ReadInput(int channel)
+{
+ s32 value = CHAN_ReadRawInput(channel);
+ if (channel <= INP_HAS_CALIBRATION) {
+ s32 max = Transmitter.calibration[channel - 1].max;
+ s32 min = Transmitter.calibration[channel - 1].min;
+ s32 zero = Transmitter.calibration[channel - 1].zero;
+ if (!zero) {
+ // If this input doesn't have a zero, calculate from max/min
+ zero = ((u32)max + min) / 2;
+ }
+ // Derate min and max by 1% to ensure we can get all the way to 100%
+ max = (max - zero) * 99 / 100;
+ min = (min - zero) * 99 / 100;
+ if (value >= zero) {
+ value = (value - zero) * CHAN_MAX_VALUE / max;
+ } else {
+ value = (value - zero) * CHAN_MIN_VALUE / min;
+ }
+ // Bound output
+ if (value > CHAN_MAX_VALUE)
+ value = CHAN_MAX_VALUE;
+ if (value < CHAN_MIN_VALUE)
+ value = CHAN_MIN_VALUE;
+ } else {
+ value = value ? CHAN_MAX_VALUE : CHAN_MIN_VALUE;
+ }
+ if (channel == INP_THROTTLE || channel == INP_AILERON || channel == INP_AUX4)
+ value = -value;
+ return value;
+}
+
+void CHAN_SetSwitchCfg(const char *str)
+{
+ if (strcmp(str, "3x4") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_3x4;
+ } else if (strcmp(str, "3x3") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_3x3;
+ } else if (strcmp(str, "3x2") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_3x2;
+ } else if (strcmp(str, "3x1") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_3x1;
+ } else if (strcmp(str, "2x8") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_2x8;
+ } else if (strcmp(str, "2x7") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_2x7;
+ } else if (strcmp(str, "2x6") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_2x6;
+ } else if (strcmp(str, "2x5") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_2x5;
+ } else if (strcmp(str, "2x4") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_2x4;
+ } else if (strcmp(str, "2x3") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_2x3;
+ } else if (strcmp(str, "2x2") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_2x2;
+ } else if (strcmp(str, "2x1") == 0) {
+ Transmitter.ignore_src &= ~SWITCH_2x1;
+ } else if (strcmp(str, "potx2") == 0) {
+ Transmitter.ignore_src &= ~POT_2;
+ } else if (strcmp(str, "potx1") == 0) {
+ Transmitter.ignore_src &= ~POT_1;
+ } else if (strcmp(str, "nostock") == 0) {
+ Transmitter.ignore_src |= SWITCH_STOCK;
+ } else {
+ Transmitter.ignore_src = ~IGNORE_MASK & ~SWITCH_STOCK;
+ }
+}
diff --git a/src/target/tx/devo/t8sg/crc.c b/src/target/tx/devo/t8sg_v1/crc.c
similarity index 100%
rename from src/target/tx/devo/t8sg/crc.c
rename to src/target/tx/devo/t8sg_v1/crc.c
diff --git a/src/target/tx/devo/t8sg_v1/hardware.h b/src/target/tx/devo/t8sg_v1/hardware.h
new file mode 100644
index 0000000000..9afd7ab08e
--- /dev/null
+++ b/src/target/tx/devo/t8sg_v1/hardware.h
@@ -0,0 +1,29 @@
+#ifndef _DEVO7E256_HARDWARE_H_
+#define _DEVO7E256_HARDWARE_H_
+
+#include "target/drivers/mcu/stm32/gpio.h"
+#include "../common/hardware_t8sg_buttonmatrix.h"
+
+// Analog inputs
+#if HAS_EXTRA_POTS
+ #define ADC_CHANNELS { \
+ ADC_CHAN(GPIOC, GPIO0), /* ADC123_10 */ \
+ ADC_CHAN(GPIOC, GPIO2), /* ADC123_12 */ \
+ ADC_CHAN(GPIOC, GPIO3), /* ADC123_13 */ \
+ ADC_CHAN(GPIOC, GPIO1), /* ADC123_11 */ \
+ ADC_CHAN(GPIOA, GPIO0), /* ADC123_0 */ \
+ ADC_CHAN(GPIOA, GPIO4), /* ADC12_4 */ \
+ ADC_CHAN(0, 16), /* TEMPERATURE */ \
+ ADC_CHAN(GPIOC, GPIO4), /* ADC12_14 */ \
+ }
+#else
+ #define ADC_CHANNELS { \
+ ADC_CHAN(GPIOC, GPIO0), /* ADC123_10 */ \
+ ADC_CHAN(GPIOC, GPIO2), /* ADC123_12 */ \
+ ADC_CHAN(GPIOC, GPIO3), /* ADC123_13 */ \
+ ADC_CHAN(GPIOC, GPIO1), /* ADC123_11 */ \
+ ADC_CHAN(0, 16), /* TEMPERATURE */ \
+ ADC_CHAN(GPIOC, GPIO4), /* ADC12_14 */ \
+ }
+#endif // HAS_EXTRA_POTS
+#endif // _DEVO7E256_HARDWARE_H_
diff --git a/src/target/tx/devo/t8sg_v1/t8sg_v1.ld b/src/target/tx/devo/t8sg_v1/t8sg_v1.ld
new file mode 100644
index 0000000000..b15aa4df03
--- /dev/null
+++ b/src/target/tx/devo/t8sg_v1/t8sg_v1.ld
@@ -0,0 +1,8 @@
+MEMORY
+{
+ /* Devo7e-256 has 256K, and bootloader takes up 12K */
+ rom (rx) : ORIGIN = 0x08003000, LENGTH = 244K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K
+}
+_crc_offset = 0x2000; /* CRC is located at 0x08005000 */
+INCLUDE target/tx/devo/common/devo.ld
diff --git a/src/target/tx/devo/t8sg_v1/target_defs.h b/src/target/tx/devo/t8sg_v1/target_defs.h
new file mode 100644
index 0000000000..3930eeb014
--- /dev/null
+++ b/src/target/tx/devo/t8sg_v1/target_defs.h
@@ -0,0 +1,67 @@
+#ifndef _T8SG_TARGET_H_
+#define _T8SG_TARGET_H_
+
+#define TXID 0x18
+#define VECTOR_TABLE_LOCATION 0x3000
+#define SPIFLASH_SECTOR_OFFSET 0
+#define SPIFLASH_SECTORS 512
+
+#define HAS_LCD_FLIPPED 1
+#define LCD_CONTRAST_FUNC(x) (x)
+
+#define HAS_STANDARD_GUI 1
+#define HAS_ADVANCED_GUI 1
+#define HAS_PERMANENT_TIMER 1
+#define HAS_TELEMETRY 1
+#define HAS_EXTENDED_TELEMETRY 1
+#define HAS_TOUCH 0
+#define HAS_RTC 0
+#define HAS_VIBRATINGMOTOR 1
+#define HAS_DATALOG 1
+#define HAS_SCANNER 1
+#define HAS_LAYOUT_EDITOR 1
+#define HAS_EXTRA_SWITCHES OPTIONAL
+#define HAS_SWITCHES_NOSTOCK 1
+#define HAS_EXTRA_BUTTONS 0
+#define HAS_EXTRA_POTS OPTIONAL
+#define HAS_MULTIMOD_SUPPORT 1
+#define HAS_VIDEO 0
+#define HAS_4IN1_FLASH 0
+#define HAS_EXTENDED_AUDIO 1
+#define HAS_AUDIO_UART 1
+#define HAS_MUSIC_CONFIG 1
+
+#ifdef BUILDTYPE_DEV
+ #define DEBUG_WINDOW_SIZE 200
+#else
+ #define DEBUG_WINDOW_SIZE 0
+#endif
+
+#define MIN_BRIGHTNESS 0
+#define DEFAULT_BATTERY_ALARM 7400
+#define DEFAULT_BATTERY_CRITICAL 7100
+#define MAX_BATTERY_ALARM 12000
+#define MIN_BATTERY_ALARM 3300
+#define MAX_POWER_ALARM 60
+
+#define NUM_OUT_CHANNELS 16
+#define NUM_VIRT_CHANNELS 10
+
+#define NUM_TRIMS 6
+#define MAX_POINTS 13
+#define NUM_MIXERS ((NUM_OUT_CHANNELS + NUM_VIRT_CHANNELS) * 4)
+
+#if HAS_EXTRA_POTS
+ #define INP_HAS_CALIBRATION 6
+#else
+ #define INP_HAS_CALIBRATION 4
+#endif
+
+/* Compute voltage from y = 2.1592x + 0.2493 */
+#define VOLTAGE_NUMERATOR 216
+#define VOLTAGE_OFFSET 249
+
+#include "hardware.h"
+#include "../common/common_devo.h"
+
+#endif // _T8SG_TARGET_H_
diff --git a/src/target/tx/devo/t8sg_v2/Makefile.inc b/src/target/tx/devo/t8sg_v2/Makefile.inc
index 2bebf9a46e..360ae2daac 100644
--- a/src/target/tx/devo/t8sg_v2/Makefile.inc
+++ b/src/target/tx/devo/t8sg_v2/Makefile.inc
@@ -1,5 +1,5 @@
SCREENSIZE := 128x64x1
-DISPLAY_DRIVER := spi/128x64x1_nt7538.c
+DISPLAY_DRIVER := spi/128x64x1.c
FILESYSTEMS := common base_fonts 128x64x1
DFU_ARGS := -c 7 -b 0x08003000
FONTS = filesystem/$(FILESYSTEM)/media/12normal.fon \
diff --git a/src/target/tx/devo/t8sg_v2_plus/Makefile.inc b/src/target/tx/devo/t8sg_v2_plus/Makefile.inc
index 04b33d1c12..360ae2daac 100644
--- a/src/target/tx/devo/t8sg_v2_plus/Makefile.inc
+++ b/src/target/tx/devo/t8sg_v2_plus/Makefile.inc
@@ -1,5 +1,5 @@
SCREENSIZE := 128x64x1
-DISPLAY_DRIVER := spi/128x64x1_oled_ssd1306.c
+DISPLAY_DRIVER := spi/128x64x1.c
FILESYSTEMS := common base_fonts 128x64x1
DFU_ARGS := -c 7 -b 0x08003000
FONTS = filesystem/$(FILESYSTEM)/media/12normal.fon \
diff --git a/src/target/tx/devo/t8sg_v2_plus/target_defs.h b/src/target/tx/devo/t8sg_v2_plus/target_defs.h
index d6d4145942..1116b8024f 100644
--- a/src/target/tx/devo/t8sg_v2_plus/target_defs.h
+++ b/src/target/tx/devo/t8sg_v2_plus/target_defs.h
@@ -6,6 +6,8 @@
#define HAS_FLASH_DETECT 1
#define SPIFLASH_SECTOR_OFFSET 0
+#define HAS_LCD_OLED 1
+
#define HAS_STANDARD_GUI 1
#define HAS_ADVANCED_GUI 1
#define HAS_PERMANENT_TIMER 1