445 lines
9.8 KiB
C++
Executable File
445 lines
9.8 KiB
C++
Executable File
/*
|
|
* Authors (alphabetical order)
|
|
* - Andre Bernet <bernet.andre@gmail.com>
|
|
* - Andreas Weitl
|
|
* - Bertrand Songis <bsongis@gmail.com>
|
|
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
|
* - Cameron Weeks <th9xer@gmail.com>
|
|
* - Erez Raviv
|
|
* - Gabriel Birkus
|
|
* - Jean-Pierre Parisy
|
|
* - Karl Szmutny
|
|
* - Michael Blandford
|
|
* - Michal Hlavinka
|
|
* - Pat Mackenzie
|
|
* - Philip Moss
|
|
* - Rob Thomson
|
|
* - Romolo Manfredini <romolo.manfredini@gmail.com>
|
|
* - Thomas Husterer
|
|
*
|
|
* opentx is based on code named
|
|
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
|
|
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
|
|
* and the original (and ongoing) project by
|
|
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
|
|
*
|
|
* 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 CS1_HIGH() TOPLCD_GPIO->BSRRL = TOPLCD_GPIO_PIN_CS1
|
|
#define CS1_LOW() TOPLCD_GPIO->BSRRH = TOPLCD_GPIO_PIN_CS1
|
|
#define CS2_HIGH() TOPLCD_GPIO->BSRRL = TOPLCD_GPIO_PIN_CS2
|
|
#define CS2_LOW() TOPLCD_GPIO->BSRRH = TOPLCD_GPIO_PIN_CS2
|
|
#define WR_HIGH() TOPLCD_GPIO->BSRRL = TOPLCD_GPIO_PIN_WR
|
|
#define WR_LOW() TOPLCD_GPIO->BSRRH = TOPLCD_GPIO_PIN_WR
|
|
#define DATA_HIGH() TOPLCD_GPIO->BSRRL = TOPLCD_GPIO_PIN_DATA
|
|
#define DATA_LOW() TOPLCD_GPIO->BSRRH = TOPLCD_GPIO_PIN_DATA
|
|
#define BL_ON() TOPLCD_GPIO->BSRRL = TOPLCD_GPIO_PIN_BL
|
|
#define BL_OFF() TOPLCD_GPIO->BSRRH = TOPLCD_GPIO_PIN_BL
|
|
|
|
const uint8_t TimeLCDsegs[] = { 0xAF, 0x06, 0x6D, 0x4F, 0xC6, 0xCB, 0xEB, 0x0E, 0xEF, 0xCF };
|
|
const uint8_t RssiLCDsegs[] = { 0xFA, 0x60, 0xBC, 0xF4, 0x66, 0xD6, 0xDE, 0x70, 0xFE, 0xF6 };
|
|
const uint8_t OpTimeLCDsegs[] = { 0x5F, 0x06, 0x6B, 0x2F, 0x36, 0x3D, 0x7D, 0x07, 0x7F, 0x3F };
|
|
|
|
uint8_t Ht1621Data1[11] = { 0 };
|
|
uint8_t Ht1621Data2[7] = { 0 };
|
|
|
|
void delay1_7us()
|
|
{
|
|
delay_01us(17);
|
|
}
|
|
|
|
void ht1621SendCommand(uint8_t chip, unsigned char command)
|
|
{
|
|
if (chip)
|
|
CS2_LOW();
|
|
else
|
|
CS1_LOW();
|
|
|
|
delay1_7us();
|
|
WR_LOW(); //PRESENT 100 COMMAND CODE
|
|
delay1_7us();
|
|
DATA_HIGH();
|
|
delay1_7us();
|
|
WR_HIGH();
|
|
delay1_7us();
|
|
WR_LOW();
|
|
delay1_7us();
|
|
DATA_LOW();
|
|
delay1_7us();
|
|
WR_HIGH();
|
|
delay1_7us();
|
|
|
|
WR_LOW();
|
|
delay1_7us();
|
|
DATA_LOW();
|
|
delay1_7us();
|
|
WR_HIGH();
|
|
delay1_7us();
|
|
|
|
for (int i=0; i<8; i++) {
|
|
WR_LOW();
|
|
delay1_7us();
|
|
if ((command & 0x80) !=0)
|
|
{
|
|
DATA_HIGH();
|
|
delay1_7us();
|
|
}
|
|
else
|
|
{
|
|
DATA_LOW();
|
|
delay1_7us();
|
|
}
|
|
WR_HIGH();
|
|
delay1_7us();
|
|
command = command << 1;
|
|
}
|
|
WR_LOW();
|
|
delay1_7us();
|
|
WR_HIGH();
|
|
delay1_7us();
|
|
|
|
if (chip)
|
|
CS2_HIGH();
|
|
else
|
|
CS1_HIGH();
|
|
|
|
delay1_7us();
|
|
}
|
|
|
|
void ht1621WrData(uint8_t data, uint8_t count)
|
|
{
|
|
while (count) {
|
|
WR_LOW();
|
|
if (data & 0x80)
|
|
DATA_HIGH();
|
|
else
|
|
DATA_LOW();
|
|
delay1_7us();
|
|
WR_HIGH();
|
|
delay1_7us();
|
|
data <<= 1;
|
|
count -= 1;
|
|
}
|
|
}
|
|
|
|
void ht1621WrAllData(uint8_t chip, uint8_t *pData)
|
|
{
|
|
int len;
|
|
if (chip) {
|
|
len = sizeof(Ht1621Data2);
|
|
CS2_LOW();
|
|
}
|
|
else {
|
|
len = sizeof(Ht1621Data1);
|
|
CS1_LOW();
|
|
}
|
|
delay1_7us();
|
|
ht1621WrData(0xa0, 3);
|
|
ht1621WrData(0, 6); // HT1621 6 bit,left 2 bit;
|
|
for (int i=0; i<len; i++) {
|
|
ht1621WrData(*pData++, 8);
|
|
}
|
|
if (chip)
|
|
CS2_HIGH();
|
|
else
|
|
CS1_HIGH();
|
|
delay1_7us();
|
|
}
|
|
|
|
#if 0
|
|
void initTimerTopLcd()
|
|
{
|
|
// Timer12
|
|
RCC->APB1ENR |= RCC_APB1ENR_TIM12EN ; // Enable clock
|
|
TIM12->ARR = 17 ; // 1.7uS
|
|
TIM12->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 10000000 - 1 ; // 0.1uS from 30MHz
|
|
TIM12->CCER = 0 ;
|
|
TIM12->CCMR1 = 0 ;
|
|
TIM12->EGR = 0 ;
|
|
TIM12->CR1 = 5 ;
|
|
// TIM12->DIER |= 1 ;
|
|
NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 2 ) ;
|
|
NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn) ;
|
|
}
|
|
|
|
extern "C" void TIM8_BRK_TIM12_IRQHandler()
|
|
{
|
|
struct t_top_lcd_control *pc ;
|
|
TIM12->SR &= ~TIM_SR_UIF ;
|
|
pc = &TopLcdControl ;
|
|
|
|
if ( pc->state == TOP_LCD_CKLOW )
|
|
{
|
|
WR_LOW() ; //PRESENT 100 COMMAND CODE
|
|
if ((*pc->data & 0x80) !=0)
|
|
{
|
|
DATA_HIGH() ;
|
|
}
|
|
else
|
|
{
|
|
DATA_LOW() ;
|
|
}
|
|
*pc->data <<= 1 ;
|
|
pc->state = TOP_LCD_CKHI ;
|
|
}
|
|
else if ( pc->state == TOP_LCD_CKHI )
|
|
{
|
|
WR_HIGH() ;
|
|
if ( --pc->count == 0 )
|
|
{
|
|
pc->state = TOP_LCD_END ;
|
|
}
|
|
else
|
|
{
|
|
pc->state = TOP_LCD_CKLOW ;
|
|
}
|
|
}
|
|
else if ( pc->state == TOP_LCD_END )
|
|
{
|
|
if ( pc->chip )
|
|
{
|
|
CS2_HIGH() ;
|
|
pc->state = TOP_LCD_IDLE ;
|
|
TIM12->DIER &= ~1 ;
|
|
}
|
|
else
|
|
{
|
|
CS1_HIGH() ;
|
|
pc->chip = 1 ;
|
|
pc->data = pc->data2 ;
|
|
pc->count = pc->count2 ;
|
|
pc->state = TOP_LCD_IDLE ;
|
|
}
|
|
}
|
|
else if ( pc->state == TOP_LCD_IDLE )
|
|
{
|
|
WR_HIGH();
|
|
if ( pc->chip ) CS2_LOW() ; else CS1_LOW() ;
|
|
pc->state = TOP_LCD_1CKLOW ;
|
|
}
|
|
else if ( pc->state == TOP_LCD_1CKLOW )
|
|
{
|
|
WR_LOW() ;
|
|
DATA_HIGH() ; // First 1 bit
|
|
pc->state = TOP_LCD_1CKHI ;
|
|
}
|
|
else if ( pc->state == TOP_LCD_1CKHI )
|
|
{
|
|
WR_HIGH() ;
|
|
if ( --pc->count == 0 )
|
|
{
|
|
pc->state = TOP_LCD_END ;
|
|
}
|
|
else
|
|
{
|
|
pc->state = TOP_LCD_CKLOW ;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void topLcdInit()
|
|
{
|
|
RCC_AHB1PeriphClockCmd(TOPLCD_RCC_AHB1Periph, ENABLE);
|
|
GPIO_InitTypeDef GPIO_InitStructure;
|
|
GPIO_InitStructure.GPIO_Pin = TOPLCD_GPIO_PIN_DATA | TOPLCD_GPIO_PIN_WR |TOPLCD_GPIO_PIN_BL|TOPLCD_GPIO_PIN_CS1|TOPLCD_GPIO_PIN_CS2;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
|
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
|
GPIO_Init(TOPLCD_GPIO, &GPIO_InitStructure);
|
|
|
|
BL_ON();
|
|
|
|
ht1621SendCommand(0, 0x03);
|
|
ht1621SendCommand(0, 0x01);
|
|
ht1621SendCommand(0, 0x29);
|
|
|
|
ht1621SendCommand(1, 0x03);
|
|
ht1621SendCommand(1, 0x01);
|
|
ht1621SendCommand(1, 0x29);
|
|
|
|
topLcdRefreshStart();
|
|
topLcdRefreshEnd();
|
|
}
|
|
|
|
void topLcdOff()
|
|
{
|
|
BL_OFF();
|
|
topLcdRefreshStart();
|
|
topLcdRefreshEnd();
|
|
}
|
|
|
|
void setTopFirstTimer(uint32_t value)
|
|
{
|
|
div_t qr = div(value, 60);
|
|
uint32_t r = qr.rem;
|
|
qr = div(qr.quot, 10) ;
|
|
|
|
// Limit to 99 min 99 sec to avoid breaking display
|
|
if (qr.quot > 9) {
|
|
qr.quot = 9;
|
|
qr.rem = 9;
|
|
r = 99;
|
|
}
|
|
|
|
Ht1621Data1[0] |= TimeLCDsegs[qr.quot] ;
|
|
Ht1621Data1[1] |= TimeLCDsegs[qr.rem] ;
|
|
qr = div(r, 10) ;
|
|
Ht1621Data1[2] |= TimeLCDsegs[qr.quot] | 0x10 ; // ":"
|
|
Ht1621Data1[3] |= TimeLCDsegs[qr.rem] | 0x10 ; // "Operation Time"
|
|
}
|
|
|
|
/*void setTopFirstTimer(uint32_t value)
|
|
{
|
|
div_t qr ;
|
|
uint32_t r ;
|
|
qr = div(value, 60) ;
|
|
r = qr.rem ;
|
|
|
|
qr = div(qr.quot, 10);
|
|
|
|
Ht1621Data1[1] |= TimeLCDsegs[qr.quot] ;
|
|
Ht1621Data1[2] |= TimeLCDsegs[qr.rem] ;
|
|
|
|
qr = div(r, 10) ;
|
|
Ht1621Data1[3] |= TimeLCDsegs[qr.quot] | 0x10 ; // ":"
|
|
Ht1621Data1[4] |= TimeLCDsegs[qr.rem] | 0x10 ; // "Operation Time"
|
|
}*/
|
|
|
|
|
|
void setTopRssiValue(uint32_t rssi)
|
|
{
|
|
div_t qr = div(rssi, 10);
|
|
uint32_t r = 0;
|
|
if (qr.quot > 9) {
|
|
r = 1;
|
|
qr.quot -= 10;
|
|
}
|
|
Ht1621Data2[2] |= r ? RssiLCDsegs[1] : 0;
|
|
Ht1621Data2[1] |= (r || qr.quot) ? RssiLCDsegs[qr.quot] : 0;
|
|
Ht1621Data2[0] |= RssiLCDsegs[qr.rem];
|
|
}
|
|
|
|
void setTopRssiBar(uint32_t rssi)
|
|
{
|
|
if (rssi > 42)
|
|
Ht1621Data2[2] |= 1 ;
|
|
if (rssi > 45)
|
|
Ht1621Data2[1] |= 1 ;
|
|
if (rssi > 50)
|
|
Ht1621Data2[0] |= 1 ;
|
|
if (rssi > 60)
|
|
Ht1621Data2[3] |= 0x10 ;
|
|
if (rssi > 70)
|
|
Ht1621Data2[3] |= 0x20 ;
|
|
if (rssi > 80)
|
|
Ht1621Data2[3] |= 0x40 ;
|
|
if (rssi > 90)
|
|
Ht1621Data2[3] |= 0x80 ;
|
|
}
|
|
|
|
void setTopRssi(uint32_t rssi)
|
|
{
|
|
Ht1621Data1[4] |= 0x10; // "RSSI"
|
|
Ht1621Data2[3] |= 0x01; // "dB"
|
|
Ht1621Data2[4] |= 0x01; // Horizontal line
|
|
setTopRssiValue(rssi);
|
|
setTopRssiBar(rssi);
|
|
}
|
|
|
|
void setTopBatteryState(uint32_t state)
|
|
{
|
|
Ht1621Data1[4] |= 0x40; // Battery border
|
|
if (state > 0)
|
|
Ht1621Data1[7] |= 0x80 ;
|
|
if (state > 1)
|
|
Ht1621Data1[9] |= 0x80 ;
|
|
if (state > 2)
|
|
Ht1621Data1[5] |= 0x80 ;
|
|
if (state > 3)
|
|
Ht1621Data1[10] |= 0x80 ;
|
|
if (state > 4)
|
|
Ht1621Data1[4] |= 0x80 ;
|
|
}
|
|
|
|
void setTopBatteryValue(uint32_t volts)
|
|
{
|
|
div_t qr ;
|
|
uint32_t r = 0 ;
|
|
uint32_t segs ;
|
|
qr = div(volts, 10) ;
|
|
if (qr.quot > 9) {
|
|
r = 1 ;
|
|
qr.quot -= 10 ;
|
|
}
|
|
segs = r ? RssiLCDsegs[1] : 0 ;
|
|
Ht1621Data2[3] |= ((segs & 7) << 1);
|
|
Ht1621Data2[4] |= segs & 0xF0 ;
|
|
segs = (r || qr.quot) ? RssiLCDsegs[qr.quot] : 0 ;
|
|
Ht1621Data2[4] |= (segs & 0x0E);
|
|
Ht1621Data2[5] |= segs & 0xF0 ;
|
|
segs = RssiLCDsegs[qr.rem] ;
|
|
Ht1621Data2[5] |= (segs & 0x0E) | 1; // Decimal point
|
|
Ht1621Data2[6] |= segs & 0xF0 ;
|
|
Ht1621Data1[4] |= 0x20; // "V"
|
|
}
|
|
|
|
void setTopSecondTimer(uint32_t value)
|
|
{
|
|
div_t qr ;
|
|
uint32_t segs ;
|
|
uint32_t segs2 ;
|
|
|
|
qr = div(value, 60);
|
|
uint32_t secs = qr.rem;
|
|
qr = div(qr.quot, 60);
|
|
uint32_t mins = qr.rem;
|
|
uint32_t hours = qr.quot;
|
|
|
|
qr = div(secs, 10) ;
|
|
segs = OpTimeLCDsegs[qr.rem] ;
|
|
Ht1621Data1[4] |= (segs & 0x0F) | 0x70 ;
|
|
segs &= 0x70 ;
|
|
segs2 = OpTimeLCDsegs[qr.quot] ;
|
|
Ht1621Data1[5] |= segs | (segs2 & 0x0F) ;
|
|
|
|
qr = div(mins, 10) ;
|
|
segs = OpTimeLCDsegs[qr.rem] ;
|
|
segs2 &= 0x70 ;
|
|
Ht1621Data1[6] |= segs2 | (segs & 0x0F) | 0x80 ; // ":"
|
|
segs &= 0x70 ;
|
|
segs2 = OpTimeLCDsegs[qr.quot] ;
|
|
Ht1621Data1[7] |= segs | (segs2 & 0x0F) ;
|
|
|
|
qr = div(hours, 10) ;
|
|
segs = OpTimeLCDsegs[qr.rem] ;
|
|
segs2 &= 0x70 ;
|
|
Ht1621Data1[8] |= segs2 | (segs & 0x0F) | 0x80 ; // ":"
|
|
segs &= 0x70 ;
|
|
segs2 = OpTimeLCDsegs[qr.quot] ;
|
|
Ht1621Data1[9] |= segs | (segs2 & 0x0F) ;
|
|
Ht1621Data1[10] |= segs2 & 0xF0 ;
|
|
}
|
|
|
|
void topLcdRefreshStart()
|
|
{
|
|
memset(Ht1621Data1, 0, sizeof(Ht1621Data1));
|
|
memset(Ht1621Data2, 0, sizeof(Ht1621Data2));
|
|
}
|
|
|
|
void topLcdRefreshEnd()
|
|
{
|
|
ht1621WrAllData(0, Ht1621Data1);
|
|
ht1621WrAllData(1, Ht1621Data2);
|
|
}
|