avr-remove remove files in main dir and targets
This commit is contained in:
@@ -1,328 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
audioQueue::audioQueue()
|
||||
{
|
||||
toneTimeLeft = 0;
|
||||
tonePause = 0;
|
||||
tone2TimeLeft = 0;
|
||||
|
||||
t_queueRidx = 0;
|
||||
t_queueWidx = 0;
|
||||
}
|
||||
|
||||
|
||||
// heartbeat is responsibile for issueing the audio tones and general square waves
|
||||
// it is essentially the life of the class.
|
||||
// it is called every 10ms
|
||||
void audioQueue::heartbeat()
|
||||
{
|
||||
#if defined(SIMU)
|
||||
return;
|
||||
#else
|
||||
if (toneTimeLeft > 0) {
|
||||
if (toneFreq == 0) { //pause only events
|
||||
speakerOff();
|
||||
}
|
||||
else {
|
||||
#if defined(CPUM2560)
|
||||
if (toneFreq) {
|
||||
OCR4A = (5000 / toneFreq); // sticking with old values approx 20(abs. min) to 90, 60 being the default tone(?).
|
||||
speakerOn();
|
||||
}
|
||||
#endif
|
||||
toneFreq += toneFreqIncr;
|
||||
}
|
||||
toneTimeLeft--; //time gets counted down
|
||||
}
|
||||
else {
|
||||
if (tonePause > 0) {
|
||||
speakerOff();
|
||||
tonePause--; //time gets counted down
|
||||
}
|
||||
else if (t_queueRidx != t_queueWidx) {
|
||||
toneFreq = queueToneFreq[t_queueRidx];
|
||||
toneTimeLeft = queueToneLength[t_queueRidx];
|
||||
toneFreqIncr = queueToneFreqIncr[t_queueRidx];
|
||||
tonePause = queueTonePause[t_queueRidx];
|
||||
if (!queueToneRepeat[t_queueRidx]--) {
|
||||
t_queueRidx = (t_queueRidx + 1) & (AUDIO_QUEUE_LENGTH-1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tone2TimeLeft > 0) {
|
||||
#if defined(CPUM2560)
|
||||
if (tone2Freq) {
|
||||
OCR4A = (5000 / tone2Freq); // sticking with old values approx 20(abs. min) to 90, 60 being the default tone(?).
|
||||
speakerOn();
|
||||
}
|
||||
#else
|
||||
toneFreq = tone2Freq;
|
||||
#endif
|
||||
tone2TimeLeft--; //time gets counted down
|
||||
}
|
||||
else {
|
||||
speakerOff();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // defined(SIMU)
|
||||
}
|
||||
|
||||
inline uint8_t audioQueue::getToneLength(uint8_t tLen)
|
||||
{
|
||||
uint8_t result = tLen; // default
|
||||
if (g_eeGeneral.beepLength < 0) {
|
||||
result /= (1-g_eeGeneral.beepLength);
|
||||
}
|
||||
if (g_eeGeneral.beepLength > 0) {
|
||||
result *= (1+g_eeGeneral.beepLength);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void audioQueue::pause(uint8_t tLen)
|
||||
{
|
||||
play(0, tLen, 5); // a pause
|
||||
}
|
||||
|
||||
void audioQueue::play(uint8_t tFreq, uint8_t tLen, uint8_t tPause, uint8_t tFlags)
|
||||
{
|
||||
if (tFlags & PLAY_BACKGROUND) {
|
||||
tone2Freq = tFreq;
|
||||
tone2TimeLeft = tLen;
|
||||
}
|
||||
else {
|
||||
int8_t tFreqIncr = (tFlags >> 6);
|
||||
if (tFreqIncr == 3) tFreqIncr = -1;
|
||||
|
||||
tFreq += g_eeGeneral.speakerPitch + BEEP_OFFSET; // add pitch compensator
|
||||
tLen = getToneLength(tLen);
|
||||
|
||||
if ((tFlags & PLAY_NOW) || (!busy() && empty())) {
|
||||
toneFreq = tFreq;
|
||||
toneTimeLeft = tLen;
|
||||
tonePause = tPause;
|
||||
toneFreqIncr = tFreqIncr;
|
||||
t_queueWidx = t_queueRidx;
|
||||
}
|
||||
else {
|
||||
tFlags++;
|
||||
}
|
||||
|
||||
tFlags &= 0x0f;
|
||||
if (tFlags) {
|
||||
uint8_t next_queueWidx = (t_queueWidx + 1) & (AUDIO_QUEUE_LENGTH-1);
|
||||
if (next_queueWidx != t_queueRidx) {
|
||||
queueToneFreq[t_queueWidx] = tFreq;
|
||||
queueToneLength[t_queueWidx] = tLen;
|
||||
queueTonePause[t_queueWidx] = tPause;
|
||||
queueToneRepeat[t_queueWidx] = tFlags - 1;
|
||||
queueToneFreqIncr[t_queueWidx] = tFreqIncr;
|
||||
t_queueWidx = next_queueWidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void audioQueue::event(uint8_t e)
|
||||
{
|
||||
#if defined(HAPTIC)
|
||||
haptic.event(e); //do this before audio to help sync timings
|
||||
#endif
|
||||
|
||||
if (e <= AU_ERROR || (e >= AU_WARNING1 && e < AU_SPECIAL_SOUND_FIRST)) {
|
||||
if (g_eeGeneral.alarmsFlash) {
|
||||
flashCounter = FLASH_DURATION;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_eeGeneral.beepMode >= e_mode_nokeys || (g_eeGeneral.beepMode >= e_mode_alarms && e <= AU_ERROR)) {
|
||||
if (e < AU_SPECIAL_SOUND_FIRST || empty()) {
|
||||
// TODO when VOICE enable some cases here are not needed!
|
||||
switch (e) {
|
||||
#if !defined(VOICE)
|
||||
case AU_TX_BATTERY_LOW:
|
||||
if (empty()) {
|
||||
play(60, 20, 3, PLAY_REPEAT(2)|PLAY_INCREMENT(1));
|
||||
play(80, 20, 3, PLAY_REPEAT(2)|PLAY_INCREMENT(-1));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case AU_SPECIAL_SOUND_RING:
|
||||
play(BEEP_DEFAULT_FREQ+25, 5, 2, PLAY_REPEAT(10));
|
||||
play(BEEP_DEFAULT_FREQ+25, 5, 10, PLAY_REPEAT(1));
|
||||
play(BEEP_DEFAULT_FREQ+25, 5, 2, PLAY_REPEAT(10));
|
||||
break;
|
||||
case AU_SPECIAL_SOUND_SCIFI:
|
||||
play(80, 10, 3, PLAY_REPEAT(2)|PLAY_INCREMENT(-1));
|
||||
play(60, 10, 3, PLAY_REPEAT(2)|PLAY_INCREMENT(1));
|
||||
play(70, 10, 1);
|
||||
break;
|
||||
case AU_SPECIAL_SOUND_ROBOT:
|
||||
play(70, 5, 1, PLAY_REPEAT(1));
|
||||
play(50, 15, 2, PLAY_REPEAT(1));
|
||||
play(80, 15, 2, PLAY_REPEAT(1));
|
||||
break;
|
||||
case AU_SPECIAL_SOUND_CHIRP:
|
||||
play(BEEP_DEFAULT_FREQ+40, 5, 1, PLAY_REPEAT(2));
|
||||
play(BEEP_DEFAULT_FREQ+54, 5, 1, PLAY_REPEAT(3));
|
||||
break;
|
||||
case AU_SPECIAL_SOUND_TADA:
|
||||
play(50, 5, 5);
|
||||
play(90, 5, 5);
|
||||
play(110, 3, 4, PLAY_REPEAT(2));
|
||||
break;
|
||||
case AU_SPECIAL_SOUND_CRICKET:
|
||||
play(80, 5, 10, PLAY_REPEAT(3));
|
||||
play(80, 5, 20, PLAY_REPEAT(1));
|
||||
play(80, 5, 10, PLAY_REPEAT(3));
|
||||
break;
|
||||
case AU_SPECIAL_SOUND_ALARMC:
|
||||
play(50, 4, 10, PLAY_REPEAT(2));
|
||||
play(70, 8, 20, PLAY_REPEAT(1));
|
||||
play(50, 8, 10, PLAY_REPEAT(2));
|
||||
play(70, 4, 20, PLAY_REPEAT(1));
|
||||
break;
|
||||
default:
|
||||
{
|
||||
static const pm_uint8_t singleSounds[] PROGMEM = {
|
||||
70, 10, 2, PLAY_REPEAT(2)|PLAY_NOW, // INACTIVITY
|
||||
BEEP_DEFAULT_FREQ, 40, 1, PLAY_NOW, // ERROR
|
||||
BEEP_DEFAULT_FREQ, 10, 1, PLAY_NOW, // WARNING1
|
||||
BEEP_DEFAULT_FREQ, 20, 1, PLAY_NOW, // WARNING2
|
||||
BEEP_DEFAULT_FREQ, 30, 1, PLAY_NOW, // WARNING3
|
||||
60, 10, 2, PLAY_NOW, // TRIM_MIDDLE
|
||||
BEEP_DEFAULT_FREQ + 50, 10, 1, PLAY_NOW, // POT_STICK_MIDDLE
|
||||
BEEP_DEFAULT_FREQ + 50, 6, 0, 0, // MIX_WARNING_1
|
||||
BEEP_DEFAULT_FREQ + 52, 6, 3, PLAY_REPEAT(1), // MIX_WARNING_2
|
||||
BEEP_DEFAULT_FREQ + 54, 6, 3, PLAY_REPEAT(2), // MIX_WARNING_3
|
||||
BEEP_DEFAULT_FREQ, 10, 1, 0, // FRSKY_BEEP1
|
||||
BEEP_DEFAULT_FREQ, 20, 1, 0, // FRSKY_BEEP2
|
||||
BEEP_DEFAULT_FREQ, 30, 1, 0, // FRSKY_BEEP3
|
||||
BEEP_DEFAULT_FREQ+20, 15, 5, PLAY_REPEAT(2), // FRSKY_WARN1
|
||||
BEEP_DEFAULT_FREQ+30, 15, 5, PLAY_REPEAT(2), // FRSKY_WARN2
|
||||
BEEP_DEFAULT_FREQ+30, 10, 2, PLAY_REPEAT(2)|PLAY_INCREMENT(2), // FRSKY_CHEEP
|
||||
BEEP_DEFAULT_FREQ+50, 5, 10, PLAY_REPEAT(10), // FRSKY_RATATA
|
||||
BEEP_DEFAULT_FREQ+50, 5, 50, PLAY_REPEAT(2), // FRSKY_TICK
|
||||
10, 20, 5, PLAY_REPEAT(2)|PLAY_INCREMENT(1), // FRSKY_SIREN
|
||||
};
|
||||
|
||||
const pm_uint8_t *ptr = &singleSounds[(e-AU_INACTIVITY)<<2];
|
||||
uint8_t tFreq = pgm_read_byte(ptr++);
|
||||
uint8_t tLen = pgm_read_byte(ptr++);
|
||||
uint8_t tPause = pgm_read_byte(ptr++);
|
||||
uint8_t tFlags = pgm_read_byte(ptr);
|
||||
play(tFreq, tLen, tPause, tFlags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void audioDefevent(uint8_t e)
|
||||
{
|
||||
audio.event(e);
|
||||
}
|
||||
|
||||
void audioKeyPress()
|
||||
{
|
||||
#if defined(AUDIO)
|
||||
if (g_eeGeneral.beepMode == e_mode_all) {
|
||||
audio.play(BEEP_DEFAULT_FREQ, 10, 1, PLAY_NOW);
|
||||
}
|
||||
#else
|
||||
beep(0);
|
||||
#endif
|
||||
|
||||
#if defined(HAPTIC)
|
||||
if (g_eeGeneral.hapticMode == e_mode_all) {
|
||||
haptic.play(5, 0, PLAY_NOW);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void audioTrimPress(int16_t value)
|
||||
{
|
||||
if (g_eeGeneral.beepMode >= e_mode_nokeys) {
|
||||
#if defined(AUDIO)
|
||||
value = limit<int16_t>(TRIM_MIN, value, TRIM_MAX);
|
||||
value >>= 2;
|
||||
value += 60;
|
||||
audio.play(value, 6, 1, PLAY_NOW);
|
||||
#else
|
||||
warble = true;
|
||||
beep(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void audioTimerCountdown(uint8_t timer, int value)
|
||||
{
|
||||
if (0) {
|
||||
// pass
|
||||
}
|
||||
|
||||
#if defined(CPUM2560) && (defined(VOICE_WTV20) || defined(VOICE_JQ6500))
|
||||
else if (g_model.timers[timer].countdownBeep == COUNTDOWN_VOICE) {
|
||||
if (value >= 0 && value <= TIMER_COUNTDOWN_START(timer)) {
|
||||
playNumber(value, 0, 0);
|
||||
}
|
||||
else if (value == 30 || value == 20) {
|
||||
playDuration(value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAPTIC)
|
||||
else if (g_model.timers[timer].countdownBeep == COUNTDOWN_HAPTIC) {
|
||||
if (value == 0) {
|
||||
haptic.play(15, 3, PLAY_NOW);
|
||||
}
|
||||
else if (value > 0 && value <= 10) {
|
||||
haptic.play(5, 0, PLAY_NOW);
|
||||
}
|
||||
else if (value == 30) {
|
||||
haptic.play(10, 3, PLAY_REPEAT(2) | PLAY_NOW);
|
||||
}
|
||||
else if (value == 20) {
|
||||
haptic.play(10, 3, PLAY_REPEAT(1) | PLAY_NOW);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
else {
|
||||
if (value == 0) {
|
||||
audio.play(BEEP_DEFAULT_FREQ + 50, 30, 3, PLAY_NOW);
|
||||
}
|
||||
else if (value > 0 && value <= 10) {
|
||||
audio.play(BEEP_DEFAULT_FREQ + 50, 15, 3, PLAY_NOW);
|
||||
}
|
||||
else if (value == 30) {
|
||||
audio.play(BEEP_DEFAULT_FREQ + 50, 15, 3, PLAY_REPEAT(2) | PLAY_NOW);
|
||||
}
|
||||
else if (value == 20) {
|
||||
audio.play(BEEP_DEFAULT_FREQ + 50, 15, 3, PLAY_REPEAT(1) | PLAY_NOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _AUDIO_AVR_H_
|
||||
#define _AUDIO_AVR_H_
|
||||
|
||||
#if defined(PCBSTD)
|
||||
#define speakerOn() buzzerOn()
|
||||
#define speakerOff() toneFreq=0; buzzerOff()
|
||||
#endif
|
||||
|
||||
//audio
|
||||
#define AUDIO_QUEUE_LENGTH (8) // 8 seems to suit most alerts
|
||||
#define BEEP_DEFAULT_FREQ (70)
|
||||
#define BEEP_OFFSET (10)
|
||||
|
||||
class audioQueue
|
||||
{
|
||||
public:
|
||||
|
||||
audioQueue();
|
||||
|
||||
void play(uint8_t tFreq, uint8_t tLen, uint8_t tPause, uint8_t tFlags=0);
|
||||
void pause(uint8_t tLen);
|
||||
|
||||
inline bool busy() { return (toneTimeLeft > 0); }
|
||||
|
||||
void event(uint8_t e);
|
||||
|
||||
inline void driver() {
|
||||
if (toneFreq) {
|
||||
toneCounter += toneFreq;
|
||||
if ((toneCounter & 0x80) == 0x80)
|
||||
buzzerOn();
|
||||
else
|
||||
buzzerOff();
|
||||
}
|
||||
}
|
||||
|
||||
// heartbeat is responsibile for issueing the audio tones and general square waves
|
||||
// it is essentially the life of the class.
|
||||
void heartbeat();
|
||||
|
||||
inline bool empty() {
|
||||
return (t_queueRidx == t_queueWidx);
|
||||
}
|
||||
|
||||
protected:
|
||||
inline uint8_t getToneLength(uint8_t tLen);
|
||||
|
||||
private:
|
||||
uint8_t t_queueRidx;
|
||||
uint8_t t_queueWidx;
|
||||
|
||||
uint8_t toneFreq;
|
||||
int8_t toneFreqIncr;
|
||||
uint8_t toneTimeLeft;
|
||||
uint8_t tonePause;
|
||||
|
||||
// vario has less priority
|
||||
uint8_t tone2Freq;
|
||||
uint8_t tone2TimeLeft;
|
||||
|
||||
// queue arrays
|
||||
uint8_t queueToneFreq[AUDIO_QUEUE_LENGTH];
|
||||
int8_t queueToneFreqIncr[AUDIO_QUEUE_LENGTH];
|
||||
uint8_t queueToneLength[AUDIO_QUEUE_LENGTH];
|
||||
uint8_t queueTonePause[AUDIO_QUEUE_LENGTH];
|
||||
uint8_t queueToneRepeat[AUDIO_QUEUE_LENGTH];
|
||||
|
||||
uint8_t toneCounter;
|
||||
|
||||
};
|
||||
|
||||
extern audioQueue audio;
|
||||
|
||||
void audioDefevent(uint8_t e);
|
||||
|
||||
#if defined(AUDIO) && defined(BUZZER)
|
||||
#define AUDIO_BUZZER(a, b) do { a; b; } while(0)
|
||||
#elif defined(AUDIO)
|
||||
#define AUDIO_BUZZER(a, b) a
|
||||
#else
|
||||
#define AUDIO_BUZZER(a, b) b
|
||||
#endif
|
||||
|
||||
#if defined(VOICE)
|
||||
#define VOICE_AUDIO_BUZZER(v, a, b) v
|
||||
#else
|
||||
#define VOICE_AUDIO_BUZZER(v, a, b) AUDIO_BUZZER(a, b)
|
||||
#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_ERROR() AUDIO_WARNING2()
|
||||
#define AUDIO_WARNING1() AUDIO_BUZZER(audioDefevent(AU_WARNING1), beep(3))
|
||||
#define AUDIO_WARNING2() AUDIO_BUZZER(audioDefevent(AU_WARNING2), beep(2))
|
||||
#define AUDIO_ERROR() AUDIO_BUZZER(audioDefevent(AU_ERROR), beep(4))
|
||||
#define AUDIO_HELLO() VOICE_AUDIO_BUZZER(PUSH_SYSTEM_PROMPT(AUDIO_HELLO),,)
|
||||
#define AUDIO_BYE()
|
||||
#define AUDIO_TX_BATTERY_LOW() VOICE_AUDIO_BUZZER(PUSH_SYSTEM_PROMPT(AU_TX_BATTERY_LOW), audioDefevent(AU_TX_BATTERY_LOW), beep(4))
|
||||
#define AUDIO_INACTIVITY() VOICE_AUDIO_BUZZER(PUSH_SYSTEM_PROMPT(AU_INACTIVITY), audioDefevent(AU_INACTIVITY), beep(3))
|
||||
#define AUDIO_ERROR_MESSAGE(e) VOICE_AUDIO_BUZZER(PUSH_SYSTEM_PROMPT((e)), audioDefevent(AU_ERROR), beep(4))
|
||||
#define AUDIO_TIMER_MINUTE(t) VOICE_AUDIO_BUZZER(playDuration(t), audioDefevent(AU_WARNING1), beep(2))
|
||||
#define AUDIO_TIMER_COUNTDOWN(idx, val) audioTimerCountdown(idx, val)
|
||||
#define AUDIO_TIMER_ELAPSED(idx) AUDIO_BUZZER(audioTimerCountdown(idx, 0), beep(3))
|
||||
|
||||
//#define AUDIO_TIMER_30() // VOICE_AUDIO_BUZZER(PUSH_SYSTEM_PROMPT(AU_TIMER_30), audioDefevent(AU_TIMER_30), { beepAgain=2; beep(2); })
|
||||
//#define AUDIO_TIMER_20() // VOICE_AUDIO_BUZZER(PUSH_SYSTEM_PROMPT(AU_TIMER_20), audioDefevent(AU_TIMER_20), { beepAgain=1; beep(2); })
|
||||
//#define AUDIO_TIMER_LT10(m, x) // AUDIO_BUZZER(audioDefevent(AU_TIMER_LT10), beep(2))
|
||||
//#define AUDIO_TIMER_00(m) // AUDIO_BUZZER(audioDefevent(AU_TIMER_00), beep(3))
|
||||
#define AUDIO_MIX_WARNING(x) AUDIO_BUZZER(audioDefevent(AU_MIX_WARNING_1+x-1), beep(1))
|
||||
#define AUDIO_POT_MIDDLE() AUDIO_BUZZER(audioDefevent(AU_POT_MIDDLE), beep(2))
|
||||
#define AUDIO_VARIO_UP() // audioDefevent(AU_KEYPAD_UP)
|
||||
#define AUDIO_VARIO_DOWN() // audioDefevent(AU_KEYPAD_DOWN)
|
||||
#define AUDIO_TRIM_MIDDLE() // AUDIO_BUZZER(audio.event(AU_TRIM_MIDDLE, f), beep(2))
|
||||
#define AUDIO_TRIM_MIN() // AUDIO_BUZZER(audioDefevent(f), beep(2))
|
||||
#define AUDIO_TRIM_MAX() // AUDIO_BUZZER(audioDefevent(f), beep(2))
|
||||
#define AUDIO_TRIM_PRESS(val) audioTrimPress(val)
|
||||
#define AUDIO_PLAY(p) audio.event(p)
|
||||
#define AUDIO_VARIO(f, t) audio.play(f, t, 0, PLAY_BACKGROUND)
|
||||
|
||||
#define AUDIO_DRIVER() audio.driver()
|
||||
#define AUDIO_HEARTBEAT() audio.heartbeat()
|
||||
#define IS_AUDIO_BUSY() audio.busy()
|
||||
#define AUDIO_RESET()
|
||||
#define AUDIO_FLUSH()
|
||||
|
||||
#define PLAY_PHASE_OFF(phase)
|
||||
#define PLAY_PHASE_ON(phase)
|
||||
#define PLAY_SWITCH_MOVED(sw)
|
||||
#define PLAY_LOGICAL_SWITCH_OFF(sw)
|
||||
#define PLAY_LOGICAL_SWITCH_ON(sw)
|
||||
#define PLAY_MODEL_NAME()
|
||||
#define START_SILENCE_PERIOD()
|
||||
|
||||
#endif // _AUDIO_AVR_H_
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
void checkBattery();
|
||||
uint8_t checkTrim(event_t event);
|
||||
|
||||
void perMain()
|
||||
{
|
||||
#if defined(SIMU)
|
||||
doMixerCalculations();
|
||||
#endif
|
||||
#if defined(LCD_ST7920)
|
||||
uint8_t lcdstate=0;
|
||||
#define IS_LCD_REFRESH_ALLOWED() (0==lcdstate)
|
||||
#else
|
||||
#define IS_LCD_REFRESH_ALLOWED() (1)
|
||||
#endif
|
||||
uint16_t t0 = getTmr16KHz();
|
||||
int16_t delta = (nextMixerEndTime - lastMixerDuration) - t0;
|
||||
if (delta > 0 && delta < MAX_MIXER_DELTA) {
|
||||
#if defined(PCBSTD) && defined(ROTARY_ENCODER_NAVIGATION)
|
||||
rotencPoll();
|
||||
#endif
|
||||
|
||||
// @@@ open.20.fsguruh
|
||||
// SLEEP(); // wouldn't that make sense? should save a lot of battery power!!!
|
||||
/* for future use; currently very very beta... */
|
||||
#if defined(POWER_SAVE)
|
||||
ADCSRA&=0x7F; // disable ADC for power saving
|
||||
ACSR&=0xF7; // disable ACIE Interrupts
|
||||
ACSR|=0x80; // disable Analog Comparator
|
||||
// maybe we disable here a lot more hardware components in future to save even more power
|
||||
|
||||
|
||||
|
||||
MCUCR|=0x20; // enable Sleep (bit5)
|
||||
// MCUCR|=0x28; // enable Sleep (bit5) enable ADC Noise Reduction (bit3)
|
||||
// first tests showed: simple sleep would reduce cpu current from 40.5mA to 32.0mA
|
||||
// noise reduction sleep would reduce it down to 28.5mA; However this would break pulses in theory
|
||||
// however with standard module, it will need about 95mA. Therefore the drop to 88mA is not much noticable
|
||||
do {
|
||||
asm volatile(" sleep \n\t"); // if _SLEEP() is not defined use this
|
||||
t0=getTmr16KHz();
|
||||
delta= (nextMixerEndTime - lastMixerDuration) - t0;
|
||||
} while ((delta>0) && (delta<MAX_MIXER_DELTA));
|
||||
|
||||
// reenabling of the hardware components needed here
|
||||
MCUCR&=0x00; // disable sleep
|
||||
ADCSRA|=0x80; // enable ADC
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
nextMixerEndTime = t0 + MAX_MIXER_DELTA;
|
||||
// this is a very tricky implementation; lastMixerEndTime is just like a default value not to stop mixcalculations totally;
|
||||
// the real value for lastMixerEndTime is calculated inside pulses_XXX.cpp which aligns the timestamp to the pulses generated
|
||||
// nextMixerEndTime is actually defined inside pulses_XXX.h
|
||||
|
||||
doMixerCalculations();
|
||||
|
||||
t0 = getTmr16KHz() - t0;
|
||||
lastMixerDuration = t0;
|
||||
if (t0 > maxMixerDuration) maxMixerDuration = t0;
|
||||
|
||||
#if defined(MODULE_ALWAYS_SEND_PULSES)
|
||||
if (startupWarningState < STARTUP_WARNING_DONE) {
|
||||
// don't do menu's until throttle and switch warnings are handled
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (eepromIsTransferComplete()) {
|
||||
if (theFile.isWriting())
|
||||
theFile.nextWriteStep();
|
||||
else if (TIME_TO_WRITE())
|
||||
storageCheck(false);
|
||||
}
|
||||
|
||||
#if defined(SDCARD)
|
||||
sdMountPoll();
|
||||
logsWrite();
|
||||
#endif
|
||||
|
||||
event_t evt = getEvent();
|
||||
evt = checkTrim(evt);
|
||||
|
||||
if (evt && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) backlightOn(); // on keypress turn the light on
|
||||
doLoopCommonActions();
|
||||
|
||||
#if defined(TELEMETRY_FRSKY) || defined(TELEMETRY_MAVLINK)
|
||||
telemetryWakeup();
|
||||
#endif
|
||||
|
||||
#if defined(NAVIGATION_STICKS)
|
||||
uint8_t sticks_evt = getSticksNavigationEvent();
|
||||
if (sticks_evt) evt = sticks_evt;
|
||||
#endif
|
||||
|
||||
#if defined(GUI)
|
||||
const char * warn = warningText;
|
||||
bool popupMenuActive = (popupMenuNoItems > 0);
|
||||
|
||||
if (IS_LCD_REFRESH_ALLOWED()) { // No need to redraw until lcdRefresh_ST7920(0) below completely refreshes the display.
|
||||
lcdClear();
|
||||
if (menuEvent) {
|
||||
menuVerticalPosition = menuEvent == EVT_ENTRY_UP ? menuVerticalPositions[menuLevel] : 0;
|
||||
menuHorizontalPosition = 0;
|
||||
evt = menuEvent;
|
||||
menuEvent = 0;
|
||||
}
|
||||
menuHandlers[menuLevel]((warn || popupMenuActive) ? 0 : evt);
|
||||
|
||||
if (warn) DISPLAY_WARNING(evt);
|
||||
#if defined(NAVIGATION_MENUS)
|
||||
if (popupMenuActive) {
|
||||
const char * result = runPopupMenu(evt);
|
||||
if (result) {
|
||||
popupMenuHandler(result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
drawStatusLine();
|
||||
}
|
||||
|
||||
#if defined(LCD_KS108)
|
||||
lcdRefreshSide();
|
||||
#elif defined(LCD_ST7920)
|
||||
lcdstate = lcdRefresh_ST7920(0);
|
||||
#else
|
||||
lcdRefresh();
|
||||
#endif
|
||||
|
||||
#endif // defined(GUI)
|
||||
|
||||
if (SLAVE_MODE()) {
|
||||
JACK_PPM_OUT();
|
||||
}
|
||||
else {
|
||||
JACK_PPM_IN();
|
||||
}
|
||||
|
||||
checkBattery();
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
option(SP22 "SmartieParts 2.2 Backlight support" OFF)
|
||||
option(PWM_BACKLIGHT "PWM Backlight" OFF)
|
||||
set(ARCH AVR)
|
||||
set(MCU atmega64)
|
||||
set(AVRDUDE_MCU m64)
|
||||
string(TOLOWER ${PCB} FLAVOUR)
|
||||
set(EEPROM_VARIANT_NEEDED ON)
|
||||
set(EEPROM EEPROM_RLC)
|
||||
set(SDCARD NO)
|
||||
set(GUI_DIR 128x64)
|
||||
set(TARGET_DIR 9x)
|
||||
set(FIRMWARE_DEPENDENCIES ${FIRMWARE_DEPENDENCIES} 9x_bitmaps)
|
||||
add_definitions(-DPCBSTD -DPCB${PCB} -DCPUM64)
|
||||
set(TARGET_SRC ${TARGET_SRC} board.cpp)
|
||||
set(GUI_SRC
|
||||
${GUI_SRC}
|
||||
model_inputs_mixes.cpp
|
||||
radio_diagkeys.cpp
|
||||
radio_diaganas.cpp
|
||||
)
|
||||
if(SP22)
|
||||
add_definitions(-DSP22)
|
||||
endif()
|
||||
if(PWM_BACKLIGHT)
|
||||
add_definitions(-DPWM_BACKLIGHT)
|
||||
endif()
|
||||
set(FIRMWARE_TARGET_SRC
|
||||
${FIRMWARE_TARGET_SRC}
|
||||
lcd_driver.cpp
|
||||
)
|
||||
|
||||
@@ -1,364 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#if defined(ROTARY_ENCODER_NAVIGATION)
|
||||
|
||||
#if defined(TELEMETREZ)
|
||||
uint8_t TrotCount; // TeZ version
|
||||
uint8_t LastTrotCount; // TeZ version
|
||||
uint8_t RotEncoder;
|
||||
#else
|
||||
uint8_t RotPosition;
|
||||
int8_t LastRotaryValue;
|
||||
int8_t Rotary_diff;
|
||||
int8_t RotaryControl;
|
||||
uint8_t RotEncoder;
|
||||
#endif
|
||||
|
||||
void rotencPoll()
|
||||
{
|
||||
#if defined(TELEMETREZ)
|
||||
if (TrotCount != LastTrotCount) {
|
||||
rotencValue[0] = LastTrotCount = TrotCount;
|
||||
}
|
||||
#else
|
||||
// Rotary Encoder polling
|
||||
PORTA = 0; // No pullups
|
||||
DDRA = 0x1F; // Top 3 bits input
|
||||
|
||||
asm(" rjmp 1f");
|
||||
asm("1:");
|
||||
|
||||
uint8_t rotary;
|
||||
rotary = PINA;
|
||||
DDRA = 0xFF; // Back to all outputs
|
||||
rotary &= 0xE0;
|
||||
|
||||
RotEncoder = rotary; // just read the lcd pin
|
||||
|
||||
rotary &= 0xDF;
|
||||
if ( rotary != RotPosition ) {
|
||||
uint8_t x;
|
||||
x = RotPosition & 0x40;
|
||||
x <<= 1;
|
||||
x ^= rotary & 0x80;
|
||||
if ( x ) {
|
||||
rotencValue[0] -= 1;
|
||||
}
|
||||
else {
|
||||
rotencValue[0] += 1;
|
||||
}
|
||||
RotPosition = rotary;
|
||||
}
|
||||
#endif // TELEMETREZ
|
||||
}
|
||||
#else
|
||||
#define ROTENC_DOWN() (0)
|
||||
#endif // ROTARY_ENCODER_NAVIGATION
|
||||
|
||||
void boardInit()
|
||||
{
|
||||
#if !defined(SIMU)
|
||||
// Set up I/O port data directions and initial states
|
||||
DDRA = 0xff; PORTA = 0x00; // LCD data
|
||||
DDRB = 0x81; PORTB = 0x7e; //pullups keys+nc
|
||||
#if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
|
||||
DDRC = 0xff; PORTC = 0x00;
|
||||
#else
|
||||
DDRC = 0x3e; PORTC = 0xc1; //pullups nc
|
||||
#endif
|
||||
DDRD = 0x00; PORTD = 0xff; //pullups keys
|
||||
DDRE = (1<<OUT_E_BUZZER); PORTE = 0xff-(1<<OUT_E_BUZZER); //pullups + buzzer 0
|
||||
DDRF = 0x00; PORTF = 0x00; //anain
|
||||
DDRG = 0x14; PORTG = 0xfb; //pullups + SIM_CTL=1 = phonejack = ppm_in, Haptic output and off (0)
|
||||
|
||||
adcInit();
|
||||
|
||||
#if defined(CPUM2561)
|
||||
TCCR2B = (0b111 << CS20); // Norm mode, clk/1024 (differs from ATmega64 chip)
|
||||
OCR2A = 156;
|
||||
TIMSK2 |= (1<<OCIE2A) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts
|
||||
#else
|
||||
// TCNT0 10ms = 16MHz/1024/156 periodic timer (9.984ms)
|
||||
// (with 1:4 duty at 157 to average 10.0ms)
|
||||
// Timer overflows at about 61Hz or once every 16ms.
|
||||
TCCR0 = (0b111 << CS00); // Norm mode, clk/1024
|
||||
OCR0 = 156;
|
||||
#endif
|
||||
|
||||
#if defined(AUDIO) || defined(VOICE)
|
||||
SET_TIMER_AUDIO_CTRL();
|
||||
#if defined(CPUM2561)
|
||||
OCR4A = 0xFF;
|
||||
RESUME_AUDIO_INTERRUPT();
|
||||
#else
|
||||
TIMSK |= (1<<OCIE0) | (1<<TOIE0) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts
|
||||
#endif
|
||||
#elif defined(PWM_BACKLIGHT)
|
||||
/** Smartieparts LED Backlight is connected to PORTB/pin7, which can be used as pwm output of timer2 **/
|
||||
#if defined(CPUM2561)
|
||||
#if defined(SP22)
|
||||
TCCR0A = (1<<WGM00)|(1<<COM0A1)|(1<<COM0A0); // inv. pwm mode, clk/64
|
||||
#else
|
||||
TCCR0A = (1<<WGM00)|(1<<COM0A1); // pwm mode, clk/64
|
||||
#endif
|
||||
TCCR0B = (0b011<<CS00);
|
||||
#else
|
||||
#if defined(SP22)
|
||||
TCCR2 = (0b011<<CS20)|(1<<WGM20)|(1<<COM21)|(1<<COM20); // inv. pwm mode, clk/64
|
||||
#else
|
||||
TCCR2 = (0b011<<CS20)|(1<<WGM20)|(1<<COM21); // pwm mode, clk/64
|
||||
#endif
|
||||
TIMSK |= (1<<OCIE0) | (1<<TOIE0); // Enable Output-Compare and Overflow interrrupts
|
||||
#endif
|
||||
#else
|
||||
#if !defined(CPUM2561)
|
||||
TIMSK |= (1<<OCIE0) | (1<<TOIE0); // Enable Output-Compare and Overflow interrrupts
|
||||
#endif
|
||||
#endif
|
||||
#endif // !defined(SIMU)
|
||||
}
|
||||
|
||||
#if !defined(SIMU) && (defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED))
|
||||
uint8_t pf7_digital[MUX_PF7_DIGITAL_MAX - MUX_PF7_DIGITAL_MIN + 1];
|
||||
/**
|
||||
* Update ADC PF7 using 14051 multiplexer
|
||||
* X0 : Battery voltage
|
||||
* X1 : AIL SW
|
||||
* X2 : THR SW
|
||||
* X3 : TRIM LEFT VERTICAL UP
|
||||
* X4 : TRIM LEFT VERTICAL DOWN
|
||||
*/
|
||||
void processMultiplexAna()
|
||||
{
|
||||
static uint8_t muxNum = MUX_BATT;
|
||||
uint8_t nextMuxNum = muxNum-1;
|
||||
|
||||
switch (muxNum) {
|
||||
case MUX_BATT:
|
||||
s_anaFilt[TX_VOLTAGE] = s_anaFilt[X14051];
|
||||
nextMuxNum = MUX_MAX;
|
||||
break;
|
||||
case MUX_AIL:
|
||||
case MUX_THR:
|
||||
case MUX_TRM_LV_UP:
|
||||
case MUX_TRM_LV_DWN:
|
||||
// Digital switch depend from input voltage
|
||||
// take half voltage to determine digital state
|
||||
pf7_digital[muxNum - MUX_PF7_DIGITAL_MIN] = (s_anaFilt[X14051] >= (s_anaFilt[TX_VOLTAGE] / 2)) ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// set the mux number for the next ADC convert,
|
||||
// stabilize voltage before ADC read.
|
||||
muxNum = nextMuxNum;
|
||||
PORTC &= ~((1 << PC7) | (1 << PC6) | (1 << PC0));
|
||||
if(muxNum & 1) PORTC |= (1 << PC7); // Mux CTRL A
|
||||
if(muxNum & 2) PORTC |= (1 << PC6); // Mux CTRL B
|
||||
if(muxNum & 4) PORTC |= (1 << PC0); // Mux CTRL C
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(SIMU) && (defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED))
|
||||
#define THR_STATE() pf7_digital[PF7_THR]
|
||||
#define AIL_STATE() pf7_digital[PF7_AIL]
|
||||
#elif defined(TELEMETRY_JETI) || defined(TELEMETRY_FRSKY) || defined(TELEMETRY_ARDUPILOT) || defined(TELEMETRY_NMEA) || defined(TELEMETRY_MAVLINK)
|
||||
#define THR_STATE() (PINC & (1<<INP_C_ThrCt))
|
||||
#define AIL_STATE() (PINC & (1<<INP_C_AileDR))
|
||||
#else
|
||||
#define THR_STATE() (PINE & (1<<INP_E_ThrCt))
|
||||
#define AIL_STATE() (PINE & (1<<INP_E_AileDR))
|
||||
#endif
|
||||
|
||||
uint8_t keyState(uint8_t index)
|
||||
{
|
||||
return keys[index].state();
|
||||
}
|
||||
|
||||
uint8_t switchState(uint8_t index)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
switch (index) {
|
||||
case SW_ELE:
|
||||
result = PINE & (1<<INP_E_ElevDR);
|
||||
break;
|
||||
|
||||
case SW_AIL:
|
||||
result = AIL_STATE();
|
||||
break;
|
||||
|
||||
case SW_RUD:
|
||||
result = PING & (1<<INP_G_RuddDR);
|
||||
break;
|
||||
// INP_G_ID1 INP_E_ID2
|
||||
// id0 0 1
|
||||
// id1 1 1
|
||||
// id2 1 0
|
||||
case SW_ID0:
|
||||
result = !(PING & (1<<INP_G_ID1));
|
||||
break;
|
||||
|
||||
case SW_ID1:
|
||||
result = (PING & (1<<INP_G_ID1)) && (PINE & (1<<INP_E_ID2));
|
||||
break;
|
||||
|
||||
case SW_ID2:
|
||||
result = !(PINE & (1<<INP_E_ID2));
|
||||
break;
|
||||
|
||||
case SW_GEA:
|
||||
result = PINE & (1<<INP_E_Gear);
|
||||
break;
|
||||
|
||||
case SW_THR:
|
||||
result = THR_STATE();
|
||||
break;
|
||||
|
||||
case SW_TRN:
|
||||
result = PINE & (1<<INP_E_Trainer);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Trim switches ...
|
||||
uint8_t trimHelper(uint8_t negpin, uint8_t idx)
|
||||
{
|
||||
switch(idx){
|
||||
case 0: return negpin & TRIMS_GPIO_PIN_LHL;
|
||||
case 1: return negpin & TRIMS_GPIO_PIN_LHR;
|
||||
#if !defined(SIMU) && defined(TELEMETRY_MOD_14051_SWAPPED)
|
||||
case 2: return !pf7_digital[PF7_TRM_LV_DWN];
|
||||
case 3: return !pf7_digital[PF7_TRM_LV_UP];
|
||||
#else
|
||||
case 2: return negpin & TRIMS_GPIO_PIN_LVD;
|
||||
case 3: return negpin & TRIMS_GPIO_PIN_LVU;
|
||||
#endif
|
||||
case 4: return negpin & TRIMS_GPIO_PIN_RVD;
|
||||
case 5: return negpin & TRIMS_GPIO_PIN_RVU;
|
||||
case 6: return negpin & TRIMS_GPIO_PIN_RHL;
|
||||
case 7: return negpin & TRIMS_GPIO_PIN_RHR;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t trimDown(uint8_t idx)
|
||||
{
|
||||
return trimHelper(~PIND, idx);
|
||||
}
|
||||
|
||||
void readKeysAndTrims()
|
||||
{
|
||||
uint8_t index = KEY_MENU;
|
||||
|
||||
// User buttons ...
|
||||
uint8_t in = ~PINB;
|
||||
for (int i=1; i<7; i++) {
|
||||
keys[index].input(in & (1<<i));
|
||||
++index;
|
||||
}
|
||||
|
||||
// Trims ...
|
||||
in = ~PIND;
|
||||
for (int i=0; i<8; i++) {
|
||||
// INP_D_TRM_RH_UP 0 .. INP_D_TRM_LH_UP 7
|
||||
keys[index].input(trimHelper(in, i));
|
||||
++index;
|
||||
}
|
||||
|
||||
#if defined(ROTARY_ENCODER_NAVIGATION)
|
||||
keys[index].input(ROTENC_DOWN()); // Rotary Enc. Switch
|
||||
#endif
|
||||
|
||||
#if defined(NAVIGATION_STICKS)
|
||||
if (~PINB & 0x7E) {
|
||||
StickScrollTimer = STICK_SCROLL_TIMEOUT;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool checkSlaveMode()
|
||||
{
|
||||
// no power -> only phone jack = slave mode
|
||||
static bool lastSlaveMode = false;
|
||||
static uint8_t checkDelay = 0;
|
||||
if (IS_AUDIO_BUSY()) {
|
||||
checkDelay = 20;
|
||||
}
|
||||
else if (checkDelay) {
|
||||
--checkDelay;
|
||||
}
|
||||
else {
|
||||
lastSlaveMode = (PING & (1<<INP_G_RF_POW));
|
||||
}
|
||||
return lastSlaveMode;
|
||||
}
|
||||
|
||||
#if defined(PWM_BACKLIGHT)
|
||||
|
||||
// exponential PWM table for linear brightness
|
||||
static const uint8_t pwmtable[16] PROGMEM =
|
||||
{
|
||||
0, 2, 3, 4, 6, 8, 11, 16, 23, 32, 45, 64, 90, 128, 181, 255
|
||||
};
|
||||
|
||||
static uint8_t bl_target;
|
||||
static uint8_t bl_current;
|
||||
|
||||
void backlightEnable()
|
||||
{
|
||||
bl_target = 15 - g_eeGeneral.blOnBright;
|
||||
}
|
||||
|
||||
void backlightDisable()
|
||||
{
|
||||
bl_target = g_eeGeneral.blOffBright;
|
||||
}
|
||||
|
||||
bool isBacklightEnabled()
|
||||
{
|
||||
return (bl_target==g_eeGeneral.blOnBright);
|
||||
}
|
||||
|
||||
void backlightFade() // called from per10ms()
|
||||
{
|
||||
if (bl_target != bl_current) {
|
||||
#if defined(CPUM2561)
|
||||
if (bl_target > bl_current)
|
||||
OCR0A = pgm_read_byte(&pwmtable[++bl_current]);
|
||||
else
|
||||
OCR0A = pgm_read_byte(&pwmtable[--bl_current]);
|
||||
#else
|
||||
if (bl_target > bl_current)
|
||||
OCR2 = pgm_read_byte(&pwmtable[++bl_current]);
|
||||
else
|
||||
OCR2 = pgm_read_byte(&pwmtable[--bl_current]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_STOCK_H_
|
||||
#define _BOARD_STOCK_H_
|
||||
|
||||
#include "../common/avr/board_avr.h"
|
||||
|
||||
//
|
||||
// elev thr
|
||||
// LV RV
|
||||
// 2 ^ 4 ^
|
||||
// 1 2
|
||||
// | rudd | aile
|
||||
// <----X--3-> LH <----X--0-> RH
|
||||
// 6 | 7 1 | 0
|
||||
// | |
|
||||
// 3 v 5 v
|
||||
//
|
||||
//PORTA 7 6 5 4 3 2 1 0
|
||||
// O O O O O O O O
|
||||
// ------------------------ LCD_DAT -----------------------
|
||||
//
|
||||
//PORTB 7 6 5 4 3 2 1 0
|
||||
// O i i i i i i O
|
||||
// light KEY_LFT KEY_RGT KEY_UP KEY_DWN KEY_EXT KEY_MEN PPM
|
||||
//
|
||||
//PORTC 7 6 5 4 3 2 1 0
|
||||
// - - O O O O O -
|
||||
// NC NC LCD_E LCD_RNW LCD_A0 LCD_RES LCD_CS1 NC
|
||||
//
|
||||
//PORTD 7 6 5 4 3 2 1 0
|
||||
// i i i i i i i i
|
||||
// TRM_D_DWN _UP TRM_C_DWN _UP TRM_B_DWN _UP TRM_A_DWN _UP
|
||||
//
|
||||
//PORTE 7 6 5 4 3 2 1 0
|
||||
// i i i i O i i i
|
||||
// PPM_IN ID2 Trainer Gear Buzzer ElevDR AileDR THRCT
|
||||
//
|
||||
//PORTF 7 6 5 4 3 2 1 0
|
||||
// ai ai ai ai ai ai ai ai
|
||||
// ANA_ BAT PITT_TRM HOV_THR HOV_PIT STCK_LH STCK_RV STCK_LV STCK_RH
|
||||
// rud thro elev aile
|
||||
//PORTG 7 6 5 4 3 2 1 0
|
||||
// - - - O i i i
|
||||
// SIM_CTL ID1 Haptic RF_POW RuddDR
|
||||
|
||||
// Board driver
|
||||
void boardInit(void);
|
||||
#define boardOff() pwrOff()
|
||||
|
||||
// Keys
|
||||
#define KEYS_GPIO_REG_MENU pinb
|
||||
#define KEYS_GPIO_PIN_MENU (1<<1)
|
||||
#define KEYS_GPIO_REG_EXIT pinb
|
||||
#define KEYS_GPIO_PIN_EXIT (1<<2)
|
||||
#define KEYS_GPIO_REG_RIGHT pinb
|
||||
#define KEYS_GPIO_PIN_RIGHT (1<<5)
|
||||
#define KEYS_GPIO_REG_LEFT pinb
|
||||
#define KEYS_GPIO_PIN_LEFT (1<<6)
|
||||
#define KEYS_GPIO_REG_UP pinb
|
||||
#define KEYS_GPIO_PIN_UP (1<<4)
|
||||
#define KEYS_GPIO_REG_DOWN pinb
|
||||
#define KEYS_GPIO_PIN_DOWN (1<<3)
|
||||
#define IS_SHIFT_KEY(index) (false)
|
||||
#define IS_SHIFT_PRESSED() (false)
|
||||
|
||||
// Trims
|
||||
#define NUM_TRIMS 4
|
||||
#define NUM_TRIMS_KEYS (NUM_TRIMS * 2)
|
||||
#define TRIMS_GPIO_REG_LHL pind
|
||||
#define TRIMS_GPIO_PIN_LHL (1<<6)
|
||||
#define TRIMS_GPIO_REG_LVD pind
|
||||
#define TRIMS_GPIO_PIN_LVD (1<<3)
|
||||
#define TRIMS_GPIO_REG_RVU pind
|
||||
#define TRIMS_GPIO_PIN_RVU (1<<4)
|
||||
#define TRIMS_GPIO_REG_RHL pind
|
||||
#define TRIMS_GPIO_PIN_RHL (1<<1)
|
||||
#define TRIMS_GPIO_REG_LHR pind
|
||||
#define TRIMS_GPIO_PIN_LHR (1<<7)
|
||||
#define TRIMS_GPIO_REG_LVU pind
|
||||
#define TRIMS_GPIO_PIN_LVU (1<<2)
|
||||
#define TRIMS_GPIO_REG_RVD pind
|
||||
#define TRIMS_GPIO_PIN_RVD (1<<5)
|
||||
#define TRIMS_GPIO_REG_RHR pind
|
||||
#define TRIMS_GPIO_PIN_RHR (1<<0)
|
||||
|
||||
#if defined(CPUM2561)
|
||||
#define TIMER_16KHZ_VECT TIMER2_OVF_vect
|
||||
#define COUNTER_16KHZ TCNT2
|
||||
#define TIMER_10MS_VECT TIMER2_COMPA_vect
|
||||
#define TIMER_10MS_COMPVAL OCR2A
|
||||
#define PAUSE_10MS_INTERRUPT() TIMSK2 &= ~(1<<OCIE2A)
|
||||
#define RESUME_10MS_INTERRUPT() TIMSK2 |= (1<<OCIE2A)
|
||||
#define PAUSE_PPMIN_INTERRUPT() TIMSK3 &= ~(1<<ICIE3)
|
||||
#define RESUME_PPMIN_INTERRUPT() TIMSK3 |= (1<<ICIE3)
|
||||
#define TIMER_AUDIO_VECT TIMER4_COMPA_vect
|
||||
#define SET_TIMER_AUDIO_CTRL() TCCR4B = (1 << WGM42) | (0b010 << CS40)
|
||||
#define PAUSE_AUDIO_INTERRUPT() TIMSK4 &= ~(1<<OCIE4A)
|
||||
#define RESUME_AUDIO_INTERRUPT() TIMSK4 |= (1<<OCIE4A)
|
||||
#else
|
||||
#define TIMER_16KHZ_VECT TIMER0_OVF_vect
|
||||
#define COUNTER_16KHZ TCNT0
|
||||
#define TIMER_10MS_VECT TIMER0_COMP_vect
|
||||
#define TIMER_10MS_COMPVAL OCR0
|
||||
#define PAUSE_10MS_INTERRUPT() TIMSK &= ~(1<<OCIE0)
|
||||
#define RESUME_10MS_INTERRUPT() TIMSK |= (1<<OCIE0)
|
||||
#define PAUSE_PPMIN_INTERRUPT() ETIMSK &= ~(1<<TICIE3)
|
||||
#define RESUME_PPMIN_INTERRUPT() ETIMSK |= (1<<TICIE3)
|
||||
#define TIMER_AUDIO_VECT TIMER2_OVF_vect
|
||||
#define SET_TIMER_AUDIO_CTRL() TCCR2 = (0b010 << CS00) // Norm mode, clk/8
|
||||
#define PAUSE_AUDIO_INTERRUPT() TIMSK &= ~(1<<TOIE2)
|
||||
#define RESUME_AUDIO_INTERRUPT() TIMSK |= (1<<TOIE2)
|
||||
#endif
|
||||
|
||||
// Power driver (none)
|
||||
#define pwrCheck() (e_power_on)
|
||||
#define pwrOff()
|
||||
#define UNEXPECTED_SHUTDOWN() (mcusr & (1 << WDRF))
|
||||
|
||||
// Trainer driver
|
||||
bool checkSlaveMode();
|
||||
#define OUT_G_SIM_CTL 4 // 1 : phone-jack=ppm_in
|
||||
#define SLAVE_MODE() checkSlaveMode()
|
||||
#define JACK_PPM_OUT() PORTG &= ~(1<<OUT_G_SIM_CTL)
|
||||
#define JACK_PPM_IN() PORTG |= (1<<OUT_G_SIM_CTL)
|
||||
|
||||
// Backlight driver
|
||||
#define OUT_B_LIGHT 7
|
||||
#if defined(PWM_BACKLIGHT)
|
||||
void backlightEnable();
|
||||
void backlightDisable();
|
||||
bool isBacklightEnabled();
|
||||
void backlightFade();
|
||||
#elif defined(SP22)
|
||||
#define backlightEnable() PORTB &= ~(1<<OUT_B_LIGHT)
|
||||
#define backlightDisable() PORTB |= (1<<OUT_B_LIGHT)
|
||||
#define isBacklightEnabled() (~PORTB & (1<<OUT_B_LIGHT))
|
||||
#else
|
||||
#define backlightEnable() PORTB |= (1<<OUT_B_LIGHT)
|
||||
#define backlightDisable() PORTB &= ~(1<<OUT_B_LIGHT)
|
||||
#define isBacklightEnabled() (PORTB & (1<<OUT_B_LIGHT))
|
||||
#endif
|
||||
#if defined(VOICE) && !defined(SIMU)
|
||||
#define BACKLIGHT_ENABLE() Voice.Backlight = 1
|
||||
#define BACKLIGHT_DISABLE() Voice.Backlight = 0
|
||||
#else
|
||||
#define BACKLIGHT_ENABLE() backlightEnable()
|
||||
#define BACKLIGHT_DISABLE() backlightDisable()
|
||||
#endif
|
||||
|
||||
#define OUT_B_PPM 0
|
||||
#define INP_E_PPM_IN 7
|
||||
#define INP_E_ID2 6
|
||||
#define INP_E_Trainer 5
|
||||
#define INP_E_Gear 4
|
||||
#define OUT_E_BUZZER 3
|
||||
#define INP_E_ElevDR 2
|
||||
|
||||
#if defined(TELEMETRY_JETI) || defined(TELEMETRY_FRSKY) || defined(TELEMETRY_ARDUPILOT) || defined(TELEMETRY_NMEA) || defined(TELEMETRY_MAVLINK)
|
||||
#define INP_C_ThrCt 6
|
||||
#define INP_C_AileDR 7
|
||||
#else
|
||||
#define INP_E_ThrCt 0
|
||||
#define INP_E_AileDR 1
|
||||
#endif
|
||||
|
||||
#define INP_G_ID1 3
|
||||
#define OUT_G_HAPTIC 2
|
||||
#define INP_G_RF_POW 1
|
||||
#define INP_G_RuddDR 0
|
||||
|
||||
// Rotary Encoder driver
|
||||
#if defined(ROTARY_ENCODER_NAVIGATION)
|
||||
extern uint8_t RotEncoder;
|
||||
#if defined(TELEMETREZ)
|
||||
#define ROTENC_DOWN() (RotEncoder != 0)
|
||||
#else
|
||||
#define ROTENC_DOWN() (RotEncoder & 0x20)
|
||||
#endif
|
||||
#else
|
||||
#define ROTENC_DOWN() (0)
|
||||
#endif
|
||||
|
||||
// Keys driver
|
||||
inline uint8_t keyDown()
|
||||
{
|
||||
return ((~PINB) & 0x7E) | ROTENC_DOWN();
|
||||
}
|
||||
|
||||
#if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
|
||||
enum MuxInput {
|
||||
MUX_BATT,
|
||||
MUX_AIL,
|
||||
MUX_PF7_DIGITAL_MIN = MUX_AIL,
|
||||
MUX_THR,
|
||||
MUX_TRM_LV_UP,
|
||||
MUX_TRM_LV_DWN,
|
||||
MUX_PF7_DIGITAL_MAX = MUX_TRM_LV_DWN,
|
||||
MUX_MAX = MUX_PF7_DIGITAL_MAX
|
||||
};
|
||||
|
||||
enum Pf7Digital {
|
||||
PF7_AIL = MUX_AIL - MUX_PF7_DIGITAL_MIN,
|
||||
PF7_THR = MUX_THR - MUX_PF7_DIGITAL_MIN,
|
||||
PF7_TRM_LV_UP = MUX_TRM_LV_UP - MUX_PF7_DIGITAL_MIN,
|
||||
PF7_TRM_LV_DWN = MUX_TRM_LV_DWN - MUX_PF7_DIGITAL_MIN,
|
||||
};
|
||||
|
||||
extern uint8_t pf7_digital[MUX_PF7_DIGITAL_MAX - MUX_PF7_DIGITAL_MIN + 1];
|
||||
void processMultiplexAna();
|
||||
#endif
|
||||
|
||||
#if defined(TELEMETRY_MOD_14051_SWAPPED)
|
||||
#define TRIMS_PRESSED() (~PIND & ~0x0c || pf7_digital[PF7_TRM_LV_UP] || pf7_digital[PF7_TRM_LV_DWN])
|
||||
#else
|
||||
#define TRIMS_PRESSED() (~PIND)
|
||||
#endif
|
||||
#define KEYS_PRESSED() (~PINB)
|
||||
|
||||
// LCD driver
|
||||
#define PORTA_LCD_DAT PORTA
|
||||
#define PORTC_LCD_CTRL PORTC
|
||||
#define OUT_C_LCD_E 5
|
||||
#define OUT_C_LCD_RnW 4
|
||||
#define OUT_C_LCD_A0 3
|
||||
#define OUT_C_LCD_RES 2
|
||||
#define OUT_C_LCD_CS1 1
|
||||
|
||||
// Rotary encoder driver
|
||||
#if defined(ROTARY_ENCODER_NAVIGATION)
|
||||
extern uint8_t RotEncoder ;
|
||||
void rotencPoll();
|
||||
#endif
|
||||
|
||||
// Haptic
|
||||
#define hapticOn() PORTG |= (1 << OUT_G_HAPTIC)
|
||||
#define hapticOff() PORTG &= ~(1 << OUT_G_HAPTIC)
|
||||
|
||||
// USB fake driver
|
||||
#define usbPlugged() false
|
||||
|
||||
// Buzzer driver
|
||||
#define buzzerOn() PORTE |= (1 << OUT_E_BUZZER)
|
||||
#define buzzerOff() PORTE &= ~(1 << OUT_E_BUZZER)
|
||||
|
||||
// Battery driver
|
||||
#define BATTERY_MIN 90 // 9V
|
||||
#define BATTERY_MAX 120 // 12V
|
||||
#define BATTERY_WARN 90 // 9V
|
||||
|
||||
// Analogs
|
||||
#define NUM_MOUSE_ANALOGS 0
|
||||
#define NUM_DUMMY_ANAS 0
|
||||
|
||||
#endif // _BOARD_STOCK_H_
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#if defined(PCBSTD) && defined(VOICE)
|
||||
volatile uint8_t LcdLock;
|
||||
#define LCD_LOCK() LcdLock = 1
|
||||
#define LCD_UNLOCK() LcdLock = 0
|
||||
#else
|
||||
#define LCD_LOCK()
|
||||
#define LCD_UNLOCK()
|
||||
#endif
|
||||
|
||||
#if defined(LCD_KS108)
|
||||
#include "targets/9x/lcd_ks108_driver.cpp"
|
||||
#elif defined(LCD_ST7920)
|
||||
#include "targets/9x/lcd_st7920_driver.cpp"
|
||||
#else
|
||||
#include "targets/9x/lcd_default_driver.cpp"
|
||||
#endif
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* 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()
|
||||
{
|
||||
static uint8_t change = 0; // toggle left or right lcd writing
|
||||
uint8_t *p;
|
||||
if (change == 0){ CS2_off; CS1_on; p = displayBuf; change = 1;} // Right
|
||||
else{ CS1_off; CS2_on; p = displayBuf + 64; change = 0;} // Left
|
||||
|
||||
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()
|
||||
{
|
||||
lcdRefreshSide();
|
||||
lcdRefreshSide();
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
uint8_t yend;
|
||||
uint8_t y_table[6]={0,13,26,39,52,64};
|
||||
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{ //Since writing to ST7920 is too slow we need to split it to five bands
|
||||
yst=y_table[state];
|
||||
yend=y_table[state+1];
|
||||
if (state==4){
|
||||
state=0;
|
||||
}
|
||||
else{
|
||||
state++;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
struct t_voice Voice ;
|
||||
|
||||
void pushPrompt(uint16_t value)
|
||||
{
|
||||
#ifdef SIMU
|
||||
TRACE("playFile(\"%04d.ad4\")", value);
|
||||
#endif
|
||||
|
||||
struct t_voice *vptr;
|
||||
vptr = voiceaddress();
|
||||
|
||||
if (vptr->VoiceQueueCount < VOICE_Q_LENGTH) {
|
||||
vptr->VoiceQueue[vptr->VoiceQueueInIndex++] = value;
|
||||
vptr->VoiceQueueInIndex &= (VOICE_Q_LENGTH - 1);
|
||||
vptr->VoiceQueueCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void pushCustomPrompt(uint8_t value)
|
||||
{
|
||||
pushPrompt(PROMPT_CUSTOM_BASE + value);
|
||||
}
|
||||
|
||||
void pushNumberPrompt(uint8_t value)
|
||||
{
|
||||
pushPrompt(PROMPT_I18N_BASE + value);
|
||||
}
|
||||
|
||||
struct t_voice *voiceaddress()
|
||||
{
|
||||
return &Voice ;
|
||||
}
|
||||
|
||||
void t_voice::voice_process(void)
|
||||
{
|
||||
if (Backlight)
|
||||
VoiceLatch |= BACKLIGHT_BIT;
|
||||
else
|
||||
VoiceLatch &= ~BACKLIGHT_BIT;
|
||||
|
||||
if (VoiceState == V_IDLE) {
|
||||
PORTB |= (1 << OUT_B_LIGHT); // Latch clock high
|
||||
if (VoiceQueueCount) {
|
||||
VoiceSerial = VoiceQueue[VoiceQueueOutIndex++];
|
||||
VoiceQueueOutIndex &= (VOICE_Q_LENGTH - 1);
|
||||
VoiceQueueCount -= 1;
|
||||
VoiceTimer = 17;
|
||||
if (VoiceSerial & 0x8000) { // Looking for sound volume 1F0-1F7
|
||||
VoiceTimer = 40;
|
||||
}
|
||||
VoiceLatch &= ~VOICE_CLOCK_BIT & ~VOICE_DATA_BIT ;
|
||||
if (VoiceSerial & 0x8000) {
|
||||
VoiceLatch |= VOICE_DATA_BIT;
|
||||
}
|
||||
PORTA_LCD_DAT = VoiceLatch ; // Latch data set
|
||||
PORTB &= ~(1<<OUT_B_LIGHT) ; // Latch clock low
|
||||
VoiceCounter = 31;
|
||||
VoiceState = V_CLOCKING;
|
||||
}
|
||||
else {
|
||||
PORTA_LCD_DAT = VoiceLatch; // Latch data set
|
||||
PORTB &= ~(1 << OUT_B_LIGHT); // Latch clock low
|
||||
}
|
||||
}
|
||||
else if (VoiceState == V_STARTUP) {
|
||||
PORTB |= (1<<OUT_B_LIGHT) ; // Latch clock high
|
||||
VoiceLatch |= VOICE_CLOCK_BIT | VOICE_DATA_BIT ;
|
||||
PORTA_LCD_DAT = VoiceLatch ; // Latch data set
|
||||
if (g_blinkTmr10ms > 60) { // Give module 1.4 secs to initialise
|
||||
VoiceState = V_WAIT_START_BUSY_OFF ;
|
||||
}
|
||||
PORTB &= ~(1<<OUT_B_LIGHT) ; // Latch clock low
|
||||
}
|
||||
else if (VoiceState != V_CLOCKING) {
|
||||
uint8_t busy;
|
||||
PORTA_LCD_DAT = VoiceLatch; // Latch data set
|
||||
PORTB |= (1 << OUT_B_LIGHT); // Drive high,pullup enabled
|
||||
DDRB &= ~(1 << OUT_B_LIGHT); // Change to input
|
||||
// delay to allow input to settle
|
||||
asm(" rjmp 1f");
|
||||
asm("1:");
|
||||
asm(" nop");
|
||||
asm(" rjmp 1f");
|
||||
asm("1:");
|
||||
busy = PINB & 0x80;
|
||||
DDRB |= (1 << OUT_B_LIGHT); // Change to output
|
||||
// The next bit guarantees the backlight output gets clocked out
|
||||
if (VoiceState == V_WAIT_BUSY_ON) { // check for busy processing here
|
||||
if (busy == 0) { // Busy is active
|
||||
VoiceState = V_WAIT_BUSY_OFF;
|
||||
}
|
||||
else {
|
||||
if (--VoiceTimer == 0) {
|
||||
VoiceState = V_WAIT_BUSY_OFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (VoiceState == V_WAIT_BUSY_OFF) { // check for busy processing here
|
||||
if (busy) { // Busy is inactive
|
||||
VoiceTimer = 3;
|
||||
VoiceState = V_WAIT_BUSY_DELAY;
|
||||
}
|
||||
}
|
||||
else if (VoiceState == V_WAIT_BUSY_DELAY) {
|
||||
if (--VoiceTimer == 0) {
|
||||
VoiceState = V_IDLE;
|
||||
}
|
||||
}
|
||||
else if (VoiceState == V_WAIT_START_BUSY_OFF) { // check for busy processing here
|
||||
if (busy) { // Busy is inactive
|
||||
VoiceTimer = 20 ;
|
||||
VoiceState = V_WAIT_BUSY_DELAY ;
|
||||
}
|
||||
}
|
||||
PORTB &= ~(1 << OUT_B_LIGHT); // Latch clock low
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Bits in VoiceLatch
|
||||
#define VOICE_CLOCK_BIT 0x01
|
||||
#define VOICE_DATA_BIT 0x02
|
||||
#define BACKLIGHT_BIT 0x04
|
||||
#define SPARE_BIT 0x08
|
||||
|
||||
#if defined(CPUM64)
|
||||
#define VOICE_Q_LENGTH 8
|
||||
#else
|
||||
#define VOICE_Q_LENGTH 16
|
||||
#endif
|
||||
|
||||
// Voice states
|
||||
#define V_STARTUP 0
|
||||
#define V_IDLE 1
|
||||
#define V_CLOCKING 2
|
||||
#define V_WAIT_BUSY_ON 3
|
||||
#define V_WAIT_BUSY_OFF 4
|
||||
#define V_WAIT_BUSY_DELAY 5
|
||||
#define V_WAIT_START_BUSY_OFF 6
|
||||
|
||||
#define PROMPT_CUSTOM_BASE 0
|
||||
#define PROMPT_I18N_BASE 256
|
||||
#define PROMPT_SYSTEM_BASE 480
|
||||
|
||||
struct t_voice
|
||||
{
|
||||
uint16_t VoiceQueue[VOICE_Q_LENGTH] ;
|
||||
uint8_t Backlight ;
|
||||
uint8_t VoiceLatch ;
|
||||
uint8_t VoiceCounter ;
|
||||
uint8_t VoiceTimer ;
|
||||
uint16_t VoiceSerial ;
|
||||
uint8_t VoiceState ;
|
||||
uint8_t VoiceQueueCount ;
|
||||
uint8_t VoiceQueueInIndex ;
|
||||
uint8_t VoiceQueueOutIndex ;
|
||||
|
||||
void voice_process( void ) ;
|
||||
};
|
||||
|
||||
extern void pushPrompt(uint16_t value);
|
||||
extern void pushCustomPrompt(uint8_t value);
|
||||
extern void pushNumberPrompt(uint8_t value);
|
||||
|
||||
extern struct t_voice *voiceaddress( void ) ;
|
||||
extern struct t_voice Voice ;
|
||||
|
||||
#define VOLUME_LEVEL_MAX 7
|
||||
#define VOLUME_LEVEL_DEF 7
|
||||
#define setScaledVolume(v) pushPrompt((v) | 0xFFF0)
|
||||
|
||||
inline bool isPlaying()
|
||||
{
|
||||
#if defined(SIMU)
|
||||
return false;
|
||||
#else
|
||||
return Voice.VoiceState != V_IDLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the Voice output
|
||||
* Check for LcdLocked (in interrupt), and voice_enabled
|
||||
*/
|
||||
#define VOICE_DRIVER() \
|
||||
if ( LcdLock == 0 ) { /* LCD not in use */ \
|
||||
struct t_voice *vptr; \
|
||||
vptr = voiceaddress(); \
|
||||
if ( vptr->VoiceState == V_CLOCKING ) { \
|
||||
if ( vptr->VoiceTimer ) { \
|
||||
vptr->VoiceTimer -= 1; \
|
||||
} \
|
||||
else { \
|
||||
PORTB |= (1<<OUT_B_LIGHT); /* Latch clock high */ \
|
||||
if ((vptr->VoiceCounter & 1) == 0) { \
|
||||
vptr->VoiceLatch &= ~VOICE_DATA_BIT; \
|
||||
if ( vptr->VoiceSerial & 0x4000 ) { \
|
||||
vptr->VoiceLatch |= VOICE_DATA_BIT; \
|
||||
} \
|
||||
vptr->VoiceSerial <<= 1; \
|
||||
} \
|
||||
vptr->VoiceLatch ^= VOICE_CLOCK_BIT; \
|
||||
PORTA_LCD_DAT = vptr->VoiceLatch; /* Latch data set */ \
|
||||
PORTB &= ~(1<<OUT_B_LIGHT); /* Latch clock low */ \
|
||||
if ( --vptr->VoiceCounter == 0 ) { \
|
||||
vptr->VoiceState = V_WAIT_BUSY_ON; \
|
||||
vptr->VoiceTimer = 5; /* 50 mS */ \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define I18N_PLAY_FUNCTION(lng, x, ...) void x(__VA_ARGS__)
|
||||
#define PLAY_FUNCTION(x, ...) void x(__VA_ARGS__)
|
||||
#define PUSH_CUSTOM_PROMPT(p, ...) pushCustomPrompt((p))
|
||||
#define PUSH_NUMBER_PROMPT(p) pushNumberPrompt((p))
|
||||
#define PUSH_SYSTEM_PROMPT(p) pushNumberPrompt(PROMPT_SYSTEM_BASE-PROMPT_I18N_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) (0) /* isPlaying() */
|
||||
#define PLAY_VALUE(v, id) playValue((v))
|
||||
@@ -1,144 +0,0 @@
|
||||
option(AUDIO "Audio support" OFF)
|
||||
set(VOICE "OFF" CACHE STRING "Voice support (OFF/ON/WTV20/JQ6500)")
|
||||
option(GRAPHICS "Additional graphics" ON)
|
||||
option(BOLD "Bold font" ON)
|
||||
option(BATTGRAPH "Battery graph" OFF)
|
||||
option(HAPTIC "Haptic support" OFF)
|
||||
|
||||
set(TELEMETRY_TYPES NONE MAVLINK ARDUPILOT FRSKY FRSKY_SPORT TELEMETREZ NMEA)
|
||||
set(TELEMETRY "NONE" CACHE STRING "Telemetry Type (${TELEMETRY_TYPES})")
|
||||
set_property(CACHE TELEMETRY PROPERTY STRINGS ${TELEMETRY_TYPES})
|
||||
|
||||
set(TTS "EN" CACHE STRING "TTS language, one of: ${TTS_LANGUAGES}")
|
||||
set_property(CACHE TTS PROPERTY STRINGS ${TTS_LANGUAGES})
|
||||
|
||||
set(LCD_TYPES DEFAULT ST7565P ST7565R ERC12864FSF ST7920 KS108)
|
||||
set(LCD "DEFAULT" CACHE STRING "LCD type (${LCD_TYPES})")
|
||||
set_property(CACHE LCD PROPERTY STRINGS ${LCD_TYPES})
|
||||
|
||||
set(DSM2 "NO" CACHE STRING "DSM2 support/interface (NO/PPM/SERIAL)")
|
||||
set_property(CACHE DSM2 PROPERTY STRINGS NO PPM SERIAL)
|
||||
|
||||
set(LUA NO)
|
||||
set(PULSES_SRC pulses_avr.cpp)
|
||||
set(SRC ${SRC} main_avr.cpp)
|
||||
set(FIRMWARE_SRC
|
||||
${FIRMWARE_SRC}
|
||||
targets/common/avr/adc_driver.cpp
|
||||
targets/common/avr/eeprom_driver.cpp
|
||||
)
|
||||
add_definitions(-DLCD_${LCD})
|
||||
if(DSM2)
|
||||
add_definitions(-DDSM2 -DDSM2_${DSM2})
|
||||
endif()
|
||||
if(SDCARD)
|
||||
set(FIRMWARE_SRC ${FIRMWARE_SRC} targets/gruvin9x/diskio.cpp)
|
||||
endif()
|
||||
if(AUDIO)
|
||||
add_definitions(-DAUDIO)
|
||||
set(SRC ${SRC} audio_avr.cpp)
|
||||
set(BUZZER OFF)
|
||||
else()
|
||||
set(BUZZER ON)
|
||||
endif()
|
||||
if(BUZZER)
|
||||
add_definitions(-DBUZZER)
|
||||
set(SRC ${SRC} buzzer.cpp)
|
||||
endif()
|
||||
if((VOICE STREQUAL ON AND NOT PCB STREQUAL MEGA2560) OR ((VOICE STREQUAL WTV20 OR VOICE STREQUAL JQ6500) AND (PCB STREQUAL MEGA2560)))
|
||||
add_definitions(-DVOICE)
|
||||
if(PCB STREQUAL MEGA2560)
|
||||
add_definitions(-DVOICE_${VOICE})
|
||||
endif()
|
||||
set(TARGET_SRC ${TARGET_SRC} voice.cpp)
|
||||
foreach(LANGUAGE ${TTS_LANGUAGES})
|
||||
string(TOUPPER ${LANGUAGE} LANGUAGE_CAPITALIZED)
|
||||
if(TTS STREQUAL ${LANGUAGE_CAPITALIZED})
|
||||
add_definitions(-DTTS_${LANGUAGE_CAPITALIZED})
|
||||
set(SRC ${SRC} translations/tts_${LANGUAGE}.cpp)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
if(GRAPHICS)
|
||||
add_definitions(-DGRAPHICS)
|
||||
endif()
|
||||
if(BOLD)
|
||||
add_definitions(-DBOLD_FONT)
|
||||
endif()
|
||||
if(BATTGRAPH)
|
||||
add_definitions(-DBATTGRAPH)
|
||||
endif()
|
||||
if(HAPTIC)
|
||||
add_definitions(-DHAPTIC)
|
||||
set(SRC ${SRC} haptic.cpp)
|
||||
endif()
|
||||
if(${TELEMETRY} STREQUAL OFF)
|
||||
add_definitions(-DTELEMETRY_NONE)
|
||||
elseif(TELEMETRY STREQUAL ARDUPILOT)
|
||||
add_definitions(-DTELEMETRY_ARDUPILOT)
|
||||
set(SRC ${SRC} telemetry/ardupilot.cpp)
|
||||
elseif(TELEMETRY STREQUAL NMEA)
|
||||
add_definitions(-DTELEMETRY_NMEA)
|
||||
set(SRC ${SRC} telemetry/nmea.cpp)
|
||||
elseif(TELEMETRY STREQUAL JETI)
|
||||
add_definitions(-DTELEMETRY_JETI)
|
||||
set(SRC ${SRC} telemetry/jeti.cpp)
|
||||
elseif(TELEMETRY STREQUAL MAVLINK)
|
||||
add_definitions(-DTELEMETRY_MAVLINK)
|
||||
include_directories(${THIRDPARTY_DIR} gui/${GUI_DIR} targets/common/avr)
|
||||
if(NOT EXISTS ${THIRDPARTY_DIR}/GCS_MAVLink/include_v1.0/mavlink_types.h)
|
||||
message(WARNING "Warning: ${THIRDPARTY_DIR}/GCS_MAVLink/include_v1.0 is empty, trying to clone submodules")
|
||||
execute_process(COMMAND git submodule update --init
|
||||
RESULT_VARIABLE GIT_SUBMODULE_RESULT
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
if(NOT ${GIT_SUBMODULE_RESULT} EQUAL 0)
|
||||
message(FATAL_ERROR "Error: Cannot clone submodule at ${THIRDPARTY_DIR}/GCS_MAVLink/include_v1.0
|
||||
If you downloaded this project as a ZIP file, please instead run
|
||||
'git clone --recursive https://github.com/opentx/opentx.git'")
|
||||
endif()
|
||||
endif()
|
||||
set(FIRMWARE_SRC
|
||||
${FIRMWARE_SRC}
|
||||
targets/common/avr/telemetry_driver.cpp
|
||||
)
|
||||
set(SRC ${SRC} telemetry/mavlink.cpp)
|
||||
set(GUI_SRC ${GUI_SRC} view_mavlink.cpp)
|
||||
math(EXPR EEPROM_VARIANT ${EEPROM_VARIANT}+${MAVLINK_VARIANT})
|
||||
elseif(TELEMETRY STREQUAL TELEMETREZ)
|
||||
add_definitions(-DTELEMETRY_TELEMETREZ)
|
||||
elseif(TELEMETRY STREQUAL FRSKY_SPORT)
|
||||
add_definitions(-DTELEMETRY_FRSKY_SPORT)
|
||||
set(SRC ${SRC} crc16.cpp telemetry/frsky_sport.cpp)
|
||||
endif()
|
||||
if(TELEMETRY STREQUAL FRSKY OR TELEMETRY STREQUAL FRSKY_SPORT OR TELEMETRY STREQUAL TELEMETREZ)
|
||||
option(FRSKY_HUB "FrSky Hub support" ON)
|
||||
option(WS_HOW_HIGH "Winged Shadow sensors support" ON)
|
||||
option(GAUGES "Telemetry gauges" OFF)
|
||||
option(GPS "GPS support" ON)
|
||||
option(VARIO "Vario support" ON)
|
||||
add_definitions(-DTELEMETRY_FRSKY)
|
||||
set(SRC ${SRC} telemetry/telemetry.cpp telemetry/telemetry_holders.cpp telemetry/frsky.cpp telemetry/frsky_d.cpp)
|
||||
set(FIRMWARE_SRC
|
||||
${FIRMWARE_SRC}
|
||||
targets/common/avr/telemetry_driver.cpp
|
||||
)
|
||||
set(GUI_SRC ${GUI_SRC} view_telemetry.cpp)
|
||||
if(FRSKY_HUB)
|
||||
add_definitions(-DFRSKY_HUB)
|
||||
endif()
|
||||
if(WS_HOW_HIGH)
|
||||
add_definitions(-DWS_HOW_HIGH)
|
||||
endif()
|
||||
if(GAUGES)
|
||||
add_definitions(-DGAUGES)
|
||||
endif()
|
||||
if(GPS)
|
||||
add_definitions(-DGPS)
|
||||
endif()
|
||||
if(VARIO)
|
||||
add_definitions(-DVARIO)
|
||||
set(SRC ${SRC} vario.cpp)
|
||||
endif()
|
||||
math(EXPR EEPROM_VARIANT ${EEPROM_VARIANT}+${FRSKY_VARIANT})
|
||||
endif()
|
||||
add_definitions(-DTIMERS=2)
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#define ADC_VREF_TYPE (1 << REFS0) // AVCC with external capacitor at AREF pin
|
||||
|
||||
void adcInit()
|
||||
{
|
||||
ADMUX = ADC_VREF_TYPE;
|
||||
ADCSRA = 0x85; // ADC enabled, pre-scaler division=32 (no interrupt, no auto-triggering)
|
||||
#if defined(CPUM2560)
|
||||
ADCSRB = (1 << MUX5);
|
||||
#endif
|
||||
}
|
||||
|
||||
void adcPrepareBandgap()
|
||||
{
|
||||
// #if structure identical to the one in getADC_bandgap()
|
||||
#if defined(PCBGRUVIN9X)
|
||||
// For PCB V4, use our own 1.2V, external reference (connected to ADC3)
|
||||
ADCSRB &= ~(1<<MUX5);
|
||||
ADMUX = 0x03|ADC_VREF_TYPE; // Switch MUX to internal reference
|
||||
#elif defined(PCBMEGA2560)
|
||||
#else
|
||||
ADMUX = 0x1E|ADC_VREF_TYPE; // Switch MUX to internal reference
|
||||
#endif
|
||||
}
|
||||
|
||||
void getADC()
|
||||
{
|
||||
for (uint8_t adc_input=0; adc_input<8; adc_input++) {
|
||||
uint16_t temp_ana;
|
||||
ADMUX = adc_input|ADC_VREF_TYPE;
|
||||
ADCSRA |= 1 << ADSC; // Start the AD conversion
|
||||
while (ADCSRA & (1 << ADSC)); // Wait for the AD conversion to complete
|
||||
temp_ana = ADC;
|
||||
ADCSRA |= 1 << ADSC; // Start the second AD conversion
|
||||
while (ADCSRA & (1 << ADSC)); // Wait for the AD conversion to complete
|
||||
temp_ana += ADC;
|
||||
s_anaFilt[adc_input] = temp_ana;
|
||||
}
|
||||
|
||||
#if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
|
||||
processMultiplexAna();
|
||||
#endif
|
||||
}
|
||||
|
||||
void getADC_bandgap()
|
||||
{
|
||||
#if defined(PCBGRUVIN9X)
|
||||
static uint8_t s_bgCheck = 0;
|
||||
static uint16_t s_bgSum = 0;
|
||||
ADCSRA |= (1 << ADSC); // request sample
|
||||
s_bgCheck += 32;
|
||||
while ((ADCSRA & (1 << ADIF))==0); // wait for sample
|
||||
ADCSRA |= (1 << ADIF);
|
||||
if (s_bgCheck == 0) { // 8x over-sample (256/32=8)
|
||||
BandGap = s_bgSum+ADC;
|
||||
s_bgSum = 0;
|
||||
}
|
||||
else {
|
||||
s_bgSum += ADC;
|
||||
}
|
||||
ADCSRB |= (1 << MUX5);
|
||||
#elif defined(PCBMEGA2560)
|
||||
BandGap = 2000;
|
||||
#else
|
||||
/*
|
||||
MCUCR|=0x28; // enable Sleep (bit5) enable ADC Noise Reduction (bit2)
|
||||
asm volatile(" sleep \n\t"); // if _SLEEP() is not defined use this
|
||||
// ADCSRA|=0x40;
|
||||
while ((ADCSRA & 0x10)==0);
|
||||
ADCSRA|=0x10; // take sample clear flag?
|
||||
BandGap=ADC;
|
||||
MCUCR&=0x08; // disable sleep
|
||||
*/
|
||||
|
||||
ADCSRA |= (1 << ADSC);
|
||||
while (ADCSRA & (1 << ADSC));
|
||||
BandGap = ADC;
|
||||
#endif
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(SIMU)
|
||||
extern volatile unsigned char pina, pinb, pinc, pind, pine, pinf, ping, pinh, pinj, pinl;
|
||||
#define PINA ~pina
|
||||
#define PINB ~pinb
|
||||
#define PINC ~pinc
|
||||
#define PIND ~pind
|
||||
#define PINE ~pine
|
||||
#define PINF ~pinf
|
||||
#define PING ~ping
|
||||
#define PINH ~pinh
|
||||
#define PINJ ~pinj
|
||||
#define PINL ~pinl
|
||||
#else
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "pgmtypes.h"
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/interrupt.h>
|
||||
#define F_CPU 16000000UL // 16 MHz
|
||||
#include <util/delay.h>
|
||||
#define pgm_read_adr(address_short) pgm_read_word(address_short)
|
||||
#include <avr/wdt.h>
|
||||
#endif
|
||||
|
||||
// ADC driver
|
||||
#define NUM_POTS 3
|
||||
#define NUM_SLIDERS 0
|
||||
#define NUM_XPOTS 0
|
||||
|
||||
enum Analogs {
|
||||
STICK1,
|
||||
STICK2,
|
||||
STICK3,
|
||||
STICK4,
|
||||
POT_FIRST,
|
||||
POT1 = POT_FIRST,
|
||||
POT2,
|
||||
POT3,
|
||||
POT_LAST = POT3,
|
||||
#if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
|
||||
// When the mod is applied, ADC7 is connected to 14051's X pin and TX_VOLTAGE
|
||||
// is connected to 14051's X0 pin (one of the multiplexed inputs). TX_VOLTAGE
|
||||
// value is filled in by processMultiplexAna().
|
||||
|
||||
// This shifts TX_VOLTAGE from 7 to 8 and makes X14051 take the 7th position
|
||||
// corresponding to ADC7.
|
||||
X14051,
|
||||
#endif
|
||||
TX_VOLTAGE,
|
||||
NUM_ANALOGS
|
||||
};
|
||||
|
||||
enum CalibratedAnalogs {
|
||||
CALIBRATED_STICK1,
|
||||
CALIBRATED_STICK2,
|
||||
CALIBRATED_STICK3,
|
||||
CALIBRATED_STICK4,
|
||||
CALIBRATED_POT_FIRST,
|
||||
CALIBRATED_POT1 = CALIBRATED_POT_FIRST,
|
||||
CALIBRATED_POT2,
|
||||
CALIBRATED_POT3,
|
||||
CALIBRATED_POT_LAST = CALIBRATED_POT3,
|
||||
NUM_CALIBRATED_ANALOGS
|
||||
};
|
||||
|
||||
void adcInit();
|
||||
void adcPrepareBandgap();
|
||||
void getADC();
|
||||
void getADC_bandgap();
|
||||
|
||||
// Keys driver
|
||||
#define NUM_SWITCHES 7
|
||||
enum EnumKeys
|
||||
{
|
||||
KEY_MENU,
|
||||
KEY_ENTER=KEY_MENU,
|
||||
KEY_EXIT,
|
||||
KEY_DOWN,
|
||||
KEY_MINUS = KEY_DOWN,
|
||||
KEY_UP,
|
||||
KEY_PLUS = KEY_UP,
|
||||
KEY_RIGHT,
|
||||
KEY_LEFT,
|
||||
|
||||
TRM_BASE,
|
||||
TRM_LH_DWN = TRM_BASE,
|
||||
TRM_LH_UP,
|
||||
TRM_LV_DWN,
|
||||
TRM_LV_UP,
|
||||
TRM_RV_DWN,
|
||||
TRM_RV_UP,
|
||||
TRM_RH_DWN,
|
||||
TRM_RH_UP,
|
||||
TRM_LAST = TRM_RH_UP,
|
||||
|
||||
#if ROTARY_ENCODERS > 0 || defined(ROTARY_ENCODER_NAVIGATION)
|
||||
BTN_REa,
|
||||
#endif
|
||||
#if ROTARY_ENCODERS > 0
|
||||
BTN_REb,
|
||||
#endif
|
||||
|
||||
NUM_KEYS
|
||||
};
|
||||
|
||||
enum EnumSwitches
|
||||
{
|
||||
SW_ID0,
|
||||
SW_ID1,
|
||||
SW_ID2,
|
||||
SW_THR,
|
||||
SW_RUD,
|
||||
SW_ELE,
|
||||
SW_AIL,
|
||||
SW_GEA,
|
||||
SW_TRN,
|
||||
};
|
||||
#define IS_3POS(sw) ((sw) == 0)
|
||||
#define IS_TOGGLE(sw) ((sw) == SWSRC_TRN)
|
||||
uint8_t keyState(uint8_t index);
|
||||
uint8_t switchState(uint8_t index);
|
||||
|
||||
// LCD driver
|
||||
#define LCD_W 128
|
||||
#define LCD_H 64
|
||||
#define LCD_DEPTH 1
|
||||
#define LCD_CONTRAST_MIN 10
|
||||
#define LCD_CONTRAST_MAX 45
|
||||
#define LCD_CONTRAST_DEFAULT 25
|
||||
void lcdRefresh(void);
|
||||
#define lcdRefreshWait()
|
||||
void lcdSetRefVolt(unsigned char val);
|
||||
void lcdSetContrast(void);
|
||||
void lcdInit(void);
|
||||
#define lcdOff()
|
||||
|
||||
#if defined(LCD_KS108)
|
||||
void lcdRefreshSide();
|
||||
#endif
|
||||
|
||||
#if defined(LCD_ST7920)
|
||||
uint8_t lcdRefresh_ST7920(uint8_t full);
|
||||
#endif
|
||||
|
||||
// EEPROM driver
|
||||
#if defined(CPUM2560) || defined(CPUM2561) || defined(CPUM128)
|
||||
#define EEPROM_SIZE 4096
|
||||
#else
|
||||
#define EEPROM_SIZE 2048
|
||||
#endif
|
||||
#if defined(SIMU)
|
||||
void eepromReadBlock(uint8_t * buffer, size_t address, size_t size);
|
||||
#else
|
||||
#define eepromReadBlock(buffer, address, size) eeprom_read_block(buffer, (const void *)address, size)
|
||||
#endif
|
||||
uint8_t eepromIsTransferComplete();
|
||||
|
||||
// USART driver (static register dispatcher)
|
||||
#define RXD_DDR1 DDRD
|
||||
#define RXD_DDR_PIN1 DDD2
|
||||
#define RXD_PORT1 PORTD
|
||||
#define RXD_PORT_PIN1 PORTD2
|
||||
#define RXD_DDR0 DDRE
|
||||
#define RXD_DDR_PIN0 DDE0
|
||||
#define RXD_PORT0 PORTE
|
||||
#define RXD_PORT_PIN0 PORTE0
|
||||
|
||||
#define _DOR_N(usart_no) DOR ## usart_no
|
||||
#define _FE_N(usart_no) FE ## usart_no
|
||||
#define _RXCIE_N(usart_no) RXCIE ## usart_no
|
||||
#define _RXC_N(usart_no) RXC ## usart_no
|
||||
#define _RXD_DDR_N(usart_no) RXD_DDR ## usart_no
|
||||
#define _RXD_DDR_PIN_N(usart_no) RXD_DDR ## usart_no
|
||||
#define _RXD_PORT_N(usart_no) RXD_DDR ## usart_no
|
||||
#define _RXD_PORT_PIN_N(usart_no) RXD_DDR ## usart_no
|
||||
#define _RXEN_N(usart_no) RXEN ## usart_no
|
||||
#define _TXCIE_N(usart_no) TXCIE ## usart_no
|
||||
#define _TXEN_N(usart_no) TXEN ## usart_no
|
||||
#define _U2X_N(usart_no) U2X ## usart_no
|
||||
#define _UBRRH_N(usart_no) UBRR ## usart_no ## H
|
||||
#define _UBRRL_N(usart_no) UBRR ## usart_no ## L
|
||||
#define _UCSRA_N(usart_no) UCSR ## usart_no ## A
|
||||
#define _UCSRB_N(usart_no) UCSR ## usart_no ## B
|
||||
#define _UCSRC_N(usart_no) UCSR ## usart_no ## C
|
||||
#define _UCSZ0_N(usart_no) UCSZ ## usart_no ## 0
|
||||
#define _UCSZ1_N(usart_no) UCSZ ## usart_no ## 1
|
||||
#define _UCSZ2_N(usart_no) UCSZ ## usart_no ## 2
|
||||
#define _UDRIE_N(usart_no) UDRIE ## usart_no
|
||||
#define _UDR_N(usart_no) UDR ## usart_no
|
||||
#define _UPE_N(usart_no) UPE ## usart_no
|
||||
#define _USART_RX_vect_N(usart_no) USART ## usart_no ## _RX_vect
|
||||
#define _USART_UDRE_vect_N(usart_no) USART ## usart_no ## _UDRE_vect
|
||||
|
||||
#define DOR_N(usart_no) _DOR_N(usart_no)
|
||||
#define FE_N(usart_no) _FE_N(usart_no)
|
||||
#define RXCIE_N(usart_no) _RXCIE_N(usart_no)
|
||||
#define RXC_N(usart_no) _RXC_N(usart_no)
|
||||
#define RXD_DDR_N(usart_no) _RXD_DDR_N(usart_no)
|
||||
#define RXD_DDR_PIN_N(usart_no) _RXD_DDR_PIN_N(usart_no)
|
||||
#define RXD_PORT_N(usart_no) _RXD_PORT_N(usart_no)
|
||||
#define RXD_PORT_PIN_N(usart_no) _RXD_PORT_PIN_N(usart_no)
|
||||
#define RXEN_N(usart_no) _RXEN_N(usart_no)
|
||||
#define TXCIE_N(usart_no) _TXCIE_N(usart_no)
|
||||
#define TXEN_N(usart_no) _TXEN_N(usart_no)
|
||||
#define U2X_N(usart_no) _U2X_N(usart_no)
|
||||
#define UBRRH_N(usart_no) _UBRRH_N(usart_no)
|
||||
#define UBRRL_N(usart_no) _UBRRL_N(usart_no)
|
||||
#define UCSRA_N(usart_no) _UCSRA_N(usart_no)
|
||||
#define UCSRB_N(usart_no) _UCSRB_N(usart_no)
|
||||
#define UCSRC_N(usart_no) _UCSRC_N(usart_no)
|
||||
#define UCSZ0_N(usart_no) _UCSZ0_N(usart_no)
|
||||
#define UCSZ1_N(usart_no) _UCSZ1_N(usart_no)
|
||||
#define UCSZ2_N(usart_no) _UCSZ2_N(usart_no)
|
||||
#define UDRIE_N(usart_no) _UDRIE_N(usart_no)
|
||||
#define UDR_N(usart_no) _UDR_N(usart_no)
|
||||
#define UPE_N(usart_no) _UPE_N(usart_no)
|
||||
#define USART_RX_vect_N(usart_no) _USART_RX_vect_N(usart_no)
|
||||
#define USART_UDRE_vect_N(usart_no) _USART_UDRE_vect_N(usart_no)
|
||||
|
||||
// Telemetry driver
|
||||
#if defined(TELEMETRY_MOD_14051_SWAPPED)
|
||||
#define TLM_USART 1
|
||||
#else
|
||||
#define TLM_USART 0
|
||||
#endif
|
||||
void telemetryPortInit();
|
||||
void telemetryPortInit(uint8_t baudrate);
|
||||
void telemetryTransmitBuffer();
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
uint16_t eeprom_pointer;
|
||||
uint8_t * eeprom_buffer_data;
|
||||
volatile int8_t eeprom_buffer_size = 0;
|
||||
|
||||
inline void eeprom_write_byte()
|
||||
{
|
||||
EEAR = eeprom_pointer;
|
||||
EEDR = *eeprom_buffer_data;
|
||||
// TODO add some define here
|
||||
#if defined (CPUM2560) || defined(CPUM2561)
|
||||
EECR |= 1<<EEMPE;
|
||||
EECR |= 1<<EEPE;
|
||||
#else
|
||||
EECR |= 1<<EEMWE;
|
||||
EECR |= 1<<EEWE;
|
||||
#endif
|
||||
eeprom_pointer++;
|
||||
eeprom_buffer_data++;
|
||||
}
|
||||
|
||||
ISR(EE_READY_vect)
|
||||
{
|
||||
if (--eeprom_buffer_size > 0) {
|
||||
eeprom_write_byte();
|
||||
}
|
||||
else {
|
||||
#if defined(CPUM2560) || defined(CPUM2561)
|
||||
EECR &= ~(1<<EERIE);
|
||||
#else
|
||||
EECR &= ~(1<<EERIE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void eepromStartWrite(uint8_t * buffer, size_t address, size_t size)
|
||||
{
|
||||
assert(eeprom_buffer_size == 0);
|
||||
|
||||
eeprom_pointer = address;
|
||||
eeprom_buffer_data = buffer;
|
||||
eeprom_buffer_size = size+1;
|
||||
|
||||
#if defined (CPUM2560) || defined(CPUM2561)
|
||||
EECR |= (1<<EERIE);
|
||||
#else
|
||||
EECR |= (1<<EERIE);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t eepromIsTransferComplete()
|
||||
{
|
||||
return eeprom_buffer_size == 0;
|
||||
}
|
||||
|
||||
void eepromWriteBlock(uint8_t * buffer, size_t address, size_t size)
|
||||
{
|
||||
eepromStartWrite(buffer, address, size);
|
||||
|
||||
if (s_sync_write) {
|
||||
while (!eepromIsTransferComplete()) {
|
||||
wdt_reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#if defined(TELEMETRY_FRSKY) || defined(TELEMETRY_MAVLINK)
|
||||
|
||||
// KEEP IN SYNC WITH GUI
|
||||
enum SERIAL_BAUDS
|
||||
{
|
||||
BAUD_4800 = 0,
|
||||
BAUD_9600,
|
||||
BAUD_14400,
|
||||
BAUD_19200,
|
||||
BAUD_38400,
|
||||
BAUD_57600,
|
||||
BAUD_58798,
|
||||
BAUD_76800
|
||||
};
|
||||
|
||||
void telemetryEnableTx(void)
|
||||
{
|
||||
UCSRB_N(TLM_USART) |= (1 << TXEN_N(TLM_USART)); // enable TX
|
||||
}
|
||||
|
||||
void telemetryEnableRx(void)
|
||||
{
|
||||
UCSRB_N(TLM_USART) |= (1 << RXEN_N(TLM_USART)); // enable RX
|
||||
UCSRB_N(TLM_USART) |= (1 << RXCIE_N(TLM_USART)); // enable Interrupt
|
||||
}
|
||||
|
||||
void processTelemetryData(uint8_t data);
|
||||
extern uint8_t telemetryRxBufferCount;
|
||||
|
||||
ISR(USART_RX_vect_N(TLM_USART))
|
||||
{
|
||||
uint8_t stat;
|
||||
uint8_t data;
|
||||
|
||||
UCSRB_N(TLM_USART) &= ~(1 << RXCIE_N(TLM_USART)); // disable Interrupt
|
||||
sei();
|
||||
|
||||
stat = UCSRA_N(TLM_USART); // USART control and Status Register 0/1 A
|
||||
|
||||
/*
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
RxC0 TxC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0
|
||||
|
||||
RxC0: Receive complete
|
||||
TXC0: Transmit Complete
|
||||
UDRE0: USART Data Register Empty
|
||||
FE0: Frame Error
|
||||
DOR0: Data OverRun
|
||||
UPE0: USART Parity Error
|
||||
U2X0: Double Tx Speed
|
||||
PCM0: MultiProcessor Comms Mode
|
||||
*/
|
||||
// rh = UCSRB_N(TLM_USART); //USART control and Status Register 0/1 B
|
||||
|
||||
/*
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
RXCIE0 TxCIE0 UDRIE0 RXEN0 TXEN0 UCSZ02 RXB80 TXB80
|
||||
|
||||
RxCIE0: Receive Complete int enable
|
||||
TXCIE0: Transmit Complete int enable
|
||||
UDRIE0: USART Data Register Empty int enable
|
||||
RXEN0: Rx Enable
|
||||
TXEN0: Tx Enable
|
||||
UCSZ02: Character Size bit 2
|
||||
RXB80: Rx data bit 8
|
||||
TXB80: Tx data bit 8
|
||||
*/
|
||||
|
||||
data = UDR_N(TLM_USART); // USART data register 0
|
||||
|
||||
if (stat & ((1 << FE_N(TLM_USART)) | (1 << DOR_N(TLM_USART)) | (1 << UPE_N(TLM_USART)))) {
|
||||
// discard buffer and start fresh on any comms error
|
||||
telemetryRxBufferCount = 0;
|
||||
}
|
||||
else {
|
||||
processTelemetryData(data);
|
||||
}
|
||||
|
||||
cli() ;
|
||||
UCSRB_N(TLM_USART) |= (1 << RXCIE_N(TLM_USART)); // enable Interrupt
|
||||
}
|
||||
|
||||
static void uart_4800(void)
|
||||
{
|
||||
#undef BAUD
|
||||
#define BAUD 4800
|
||||
#include <util/setbaud.h>
|
||||
UBRRH_N(TLM_USART) = UBRRH_VALUE;
|
||||
UBRRL_N(TLM_USART) = UBRRL_VALUE;
|
||||
#if defined USE_2X
|
||||
UCSRA_N(TLM_USART) |= (1 << U2X_N(TLM_USART)); // enable double speed operation.
|
||||
#else
|
||||
UCSRA_N(TLM_USART) &= ~(1 << U2X_N(TLM_USART)); // disable double speed operation.
|
||||
#endif
|
||||
}
|
||||
|
||||
FORCEINLINE void uart_9600(void)
|
||||
{
|
||||
#undef BAUD
|
||||
#define BAUD 9600
|
||||
#include <util/setbaud.h>
|
||||
UBRRH_N(TLM_USART) = UBRRH_VALUE;
|
||||
UBRRL_N(TLM_USART) = UBRRL_VALUE;
|
||||
#if defined USE_2X
|
||||
UCSRA_N(TLM_USART) |= (1 << U2X_N(TLM_USART)); // enable double speed operation.
|
||||
#else
|
||||
UCSRA_N(TLM_USART) &= ~(1 << U2X_N(TLM_USART)); // disable double speed operation.
|
||||
#endif
|
||||
}
|
||||
|
||||
static void uart_14400(void)
|
||||
{
|
||||
#undef BAUD
|
||||
#define BAUD 14400
|
||||
#include <util/setbaud.h>
|
||||
UBRRH_N(TLM_USART) = UBRRH_VALUE;
|
||||
UBRRL_N(TLM_USART) = UBRRL_VALUE;
|
||||
#if defined USE_2X
|
||||
UCSRA_N(TLM_USART) |= (1 << U2X_N(TLM_USART)); // enable double speed operation.
|
||||
#else
|
||||
UCSRA_N(TLM_USART) &= ~(1 << U2X_N(TLM_USART)); // disable double speed operation.
|
||||
#endif
|
||||
}
|
||||
|
||||
static void uart_19200(void)
|
||||
{
|
||||
#undef BAUD
|
||||
#define BAUD 19200
|
||||
#include <util/setbaud.h>
|
||||
UBRRH_N(TLM_USART) = UBRRH_VALUE;
|
||||
UBRRL_N(TLM_USART) = UBRRL_VALUE;
|
||||
#if defined USE_2X
|
||||
UCSRA_N(TLM_USART) |= (1 << U2X_N(TLM_USART)); // enable double speed operation.
|
||||
#else
|
||||
UCSRA_N(TLM_USART) &= ~(1 << U2X_N(TLM_USART)); // disable double speed operation.
|
||||
#endif
|
||||
}
|
||||
|
||||
static void uart_38400(void)
|
||||
{
|
||||
#undef BAUD
|
||||
#define BAUD 38400
|
||||
#include <util/setbaud.h>
|
||||
UBRRH_N(TLM_USART) = UBRRH_VALUE;
|
||||
UBRRL_N(TLM_USART) = UBRRL_VALUE;
|
||||
#if defined USE_2X
|
||||
UCSRA_N(TLM_USART) |= (1 << U2X_N(TLM_USART)); // enable double speed operation.
|
||||
#else
|
||||
UCSRA_N(TLM_USART) &= ~(1 << U2X_N(TLM_USART)); // disable double speed operation.
|
||||
#endif
|
||||
}
|
||||
|
||||
static void uart_57600(void)
|
||||
{
|
||||
#undef BAUD
|
||||
#define BAUD 57600
|
||||
#include <util/setbaud.h>
|
||||
UBRRH_N(TLM_USART) = UBRRH_VALUE;
|
||||
UBRRL_N(TLM_USART) = UBRRL_VALUE;
|
||||
#if defined USE_2X
|
||||
UCSRA_N(TLM_USART) |= (1 << U2X_N(TLM_USART)); // enable double speed operation.
|
||||
#else
|
||||
UCSRA_N(TLM_USART) &= ~(1 << U2X_N(TLM_USART)); // disable double speed operation.
|
||||
#endif
|
||||
}
|
||||
|
||||
static void uart_58798(void)
|
||||
{
|
||||
UBRRH_N(TLM_USART) = 0;
|
||||
UBRRL_N(TLM_USART) = 0x010;
|
||||
UCSRA_N(TLM_USART) &= ~(1 << U2X_N(TLM_USART)); // disable double speed operation.
|
||||
}
|
||||
|
||||
static void uart_76800(void)
|
||||
{
|
||||
#undef BAUD
|
||||
#define BAUD 76800
|
||||
#include <util/setbaud.h>
|
||||
UBRRH_N(TLM_USART) = UBRRH_VALUE;
|
||||
UBRRL_N(TLM_USART) = UBRRL_VALUE;
|
||||
#if defined USE_2X
|
||||
UCSRA_N(TLM_USART) |= (1 << U2X_N(TLM_USART)); // enable double speed operation.
|
||||
#else
|
||||
UCSRA_N(TLM_USART) &= ~(1 << U2X_N(TLM_USART)); // disable double speed operation.
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(SIMU)
|
||||
FORCEINLINE void telemetryPortInit(uint8_t baudrate)
|
||||
{
|
||||
RXD_DDR_N(TLM_USART) &= ~(1 << RXD_DDR_PIN_N(TLM_USART)); // set RXD pin as input
|
||||
RXD_PORT_N(TLM_USART) &= ~(1 << RXD_PORT_PIN_N(TLM_USART)); // disable pullup on RXD pin
|
||||
switch (baudrate) {
|
||||
case BAUD_4800:
|
||||
uart_4800();
|
||||
break;
|
||||
case BAUD_9600:
|
||||
uart_9600();
|
||||
break;
|
||||
case BAUD_14400:
|
||||
uart_14400();
|
||||
break;
|
||||
case BAUD_19200:
|
||||
uart_19200();
|
||||
break;
|
||||
case BAUD_38400:
|
||||
uart_38400();
|
||||
break;
|
||||
case BAUD_58798:
|
||||
uart_58798();
|
||||
break;
|
||||
case BAUD_76800:
|
||||
uart_76800();
|
||||
break;
|
||||
default:
|
||||
uart_57600();
|
||||
break;
|
||||
}
|
||||
|
||||
// set 8N1
|
||||
UCSRB_N(TLM_USART) = 0 | (0 << RXCIE_N(TLM_USART)) | (0 << TXCIE_N(TLM_USART)) | (0 << UDRIE_N(TLM_USART)) | (0 << RXEN_N(TLM_USART)) | (0 << TXEN_N(TLM_USART)) | (0 << UCSZ2_N(TLM_USART));
|
||||
UCSRC_N(TLM_USART) = 0 | (1 << UCSZ1_N(TLM_USART)) | (1 << UCSZ0_N(TLM_USART));
|
||||
|
||||
while (UCSRA_N(TLM_USART) & (1 << RXC_N(TLM_USART))) UDR_N(TLM_USART); // flush receive buffer
|
||||
|
||||
// These should be running right from power up on a FrSky enabled '9X.
|
||||
#if defined(TELEMETRY_FRSKY)
|
||||
telemetryEnableTx(); // enable FrSky-Telemetry emission
|
||||
#endif
|
||||
telemetryEnableRx(); // enable FrSky-Telemetry reception
|
||||
}
|
||||
#endif
|
||||
|
||||
void telemetryTransmitBuffer()
|
||||
{
|
||||
UCSRB_N(TLM_USART) |= (1 << UDRIE_N(TLM_USART)); // enable UDRE1 interrupt
|
||||
}
|
||||
|
||||
void telemetryPortInit()
|
||||
{
|
||||
telemetryPortInit(BAUD_9600);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
set(ARCH AVR)
|
||||
set(MCU atmega2560)
|
||||
set(AVRDUDE_MCU m2560)
|
||||
string(TOLOWER ${PCB} FLAVOUR)
|
||||
set(EEPROM EEPROM_RLC)
|
||||
add_definitions(-DEEPROM_VARIANT=0)
|
||||
set(SDCARD NO)
|
||||
set(GUI_DIR 128x64)
|
||||
set(TARGET_DIR gruvin9x)
|
||||
set(FIRMWARE_DEPENDENCIES ${FIRMWARE_DEPENDENCIES} 9x_bitmaps)
|
||||
add_definitions(-DPCB${PCB} -DCPUM2560 -DROTARY_ENCODERS=2)
|
||||
set(TARGET_SRC ${TARGET_SRC} board.cpp)
|
||||
set(GUI_SRC
|
||||
${GUI_SRC}
|
||||
model_inputs_mixes.cpp
|
||||
radio_diagkeys.cpp
|
||||
radio_diaganas.cpp
|
||||
)
|
||||
set(FIRMWARE_SRC ${FIRMWARE_SRC} targets/9x/lcd_driver.cpp)
|
||||
@@ -1,294 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
void boardInit()
|
||||
{
|
||||
#if !defined(SIMU)
|
||||
// Set up I/O port data directions and initial states
|
||||
DDRA = 0xff; PORTA = 0x00; // LCD data
|
||||
DDRB = 0b11000111; PORTB = 0b00111111; // 7:SPKR, 6:PPM_OUT, 5:TrainSW, 4:IDL2_SW, SDCARD[3:MISO 2:MOSI 1:SCK 0:CS]
|
||||
DDRC = 0x3f; PORTC = 0xc0; // 7:AilDR, 6:EleDR, LCD[5,4,3,2,1], 0:BackLight
|
||||
DDRD = 0b11000000; PORTD = 0b11111100; // 7:VIB, 6:LED BL, 5:RENC2_PUSH, 4:RENC1_PUSH, 3:RENC2_B, 2:RENC2_A, 1:I2C_SDA, 0:I2C_SCL
|
||||
DDRE = 0b00001010; PORTE = 0b11110100; // 7:PPM_IN, 6: RENC1_B, 5:RENC1_A, 4:USB_DNEG, 3:BUZZER, 2:USB_DPOS, 1:TELEM_TX, 0:TELEM_RX(pull-up off)
|
||||
DDRF = 0x00; PORTF = 0x00; // 7-4:JTAG, 3:ADC_REF_1.2V input, 2-0:ADC_SPARE_2-0
|
||||
DDRG = 0b00010000; PORTG = 0xff; // 7-6:N/A, 5:GearSW, 4: Sim_Ctrl[out], 3:IDL1_Sw, 2:TCut_Sw, 1:RF_Power[in], 0: RudDr_Sw
|
||||
|
||||
#if defined(DEBUG) && !defined(VOICE)
|
||||
DDRH = 0b11111000; PORTH = 0b11010111; // PORTH:7-6 enabled for timing analysis output ... see below ...
|
||||
#else
|
||||
DDRH = 0b10111000; PORTH = 0b11010111; // [7:0 DSM/PPM TX-caddy control. 1=PPM, 0=DSM ]
|
||||
// [6:SOMO14D-BUSY 5:SOMO14D-DATA 4:SOMO14D-CLK 3:SOMO14D-RESET]
|
||||
// [2:VIB_OPTION -- setting to input for now]
|
||||
// [1:TxD 0:RxD Spare serial port]
|
||||
#endif
|
||||
|
||||
DDRJ = 0x00; PORTJ = 0xff; // 7-0:Trim switch inputs
|
||||
DDRK = 0x00; PORTK = 0x00; // anain. No pull-ups!
|
||||
#ifdef REV0
|
||||
DDRL = 0x80; PORTL = 0x7f; // 7: Hold_PWR_On (1=On, default Off), 6:Jack_Presence_TTL, 5-0: User Button inputs
|
||||
#else
|
||||
DDRL = 0x80; PORTL = 0xff; // 7: Hold_PWR_On (1=On, default Off), 6:Jack_Presence_TTL, 5-0: User Button inputs
|
||||
#endif
|
||||
|
||||
adcInit();
|
||||
|
||||
/**** Set up timer/counter 0 ****/
|
||||
/** Move old 64A Timer0 functions to Timer2 and use WGM on OC0(A) (PB7) for spkear tone output **/
|
||||
|
||||
// TCNT0 10ms = 16MHz/1024/156(.25) periodic timer (100ms interval)
|
||||
// cycles at 9.984ms but includes 1:4 duty cycle correction to /157 to average at 10.0ms
|
||||
TCCR2B = (0b111 << CS20); // Norm mode, clk/1024 (differs from ATmega64 chip)
|
||||
OCR2A = 156;
|
||||
TIMSK2 |= (1<<OCIE2A) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts
|
||||
|
||||
// Set up Phase correct Waveform Gen. mode, at clk/64 = 250,000 counts/second
|
||||
// (Higher speed allows for finer control of frquencies in the audio range.)
|
||||
// Used for audio tone generation
|
||||
TCCR0B = (1<<WGM02) | (0b011 << CS00);
|
||||
TCCR0A = (0b01<<WGM00);
|
||||
|
||||
/***************************************************/
|
||||
/* Rotary encoder interrupt set-up (V4 board only) */
|
||||
|
||||
// All external interrupts initialise to disabled. But maybe not after
|
||||
// a WDT or BOD event? So to be safe ...
|
||||
EIMSK = 0; // disable ALL external interrupts.
|
||||
|
||||
// encoder 1
|
||||
EICRB = (1<<ISC60) | (1<<ISC50); // 01 = interrupt on any edge
|
||||
EIFR = (3<<INTF5); // clear the int. flag in case it got set when changing modes
|
||||
|
||||
// encoder 2
|
||||
EICRA = (1<<ISC30) | (1<<ISC20); // do the same for encoder 1
|
||||
EIFR = (3<<INTF2);
|
||||
|
||||
#if ROTARY_ENCODERS > 2
|
||||
EIMSK = (3<<INT5); // enable the ONE rot. enc. ext. int. pairs.
|
||||
#else
|
||||
EIMSK = (3<<INT5) | (3<<INT2); // enable the two rot. enc. ext. int. pairs.
|
||||
#endif
|
||||
/***************************************************/
|
||||
|
||||
#if defined(VOICE)
|
||||
/*
|
||||
* SOMO set-up (V4 board only)
|
||||
*/
|
||||
OCR4A = 0x1F4; //2ms
|
||||
TCCR4B = (1 << WGM42) | (0b011 << CS40); // CTC OCR1A, 16MHz / 64 (4us ticks)
|
||||
TIMSK4 |= (1<<OCIE4A); // Start the interrupt so the unit reset can occur
|
||||
#endif
|
||||
|
||||
#if ROTARY_ENCODERS > 2
|
||||
//configure uart1 here
|
||||
DDRD &= ~(1 << 2);
|
||||
PORTD &= ~(1 << 2);
|
||||
#define EXTRA_ROTARY_ENCODERS_USART_BAUD 9600UL
|
||||
UBRR1 = F_CPU/(16*EXTRA_ROTARY_ENCODERS_USART_BAUD)-1;
|
||||
//9 bit mode
|
||||
UCSR1C = (1<<USBS1)|(3<<UCSZ10);
|
||||
UCSR1B = (1<<RXEN1)|(0<<TXEN1)|(1<<UCSZ12);
|
||||
UCSR1B |= 1 << RXCIE1; //enable interrupt on rx
|
||||
#endif
|
||||
#endif // !defined(SIMU)
|
||||
}
|
||||
|
||||
#if ROTARY_ENCODERS > 2
|
||||
uint8_t vpotToChange = 0;
|
||||
uint8_t vpot_mod_state = 0;
|
||||
|
||||
ISR(USART1_RX_vect)
|
||||
{
|
||||
//receive data from extension board
|
||||
//bit 9 = 1 mean encoder number, following byte with bit 9 = 0 is increment value
|
||||
/* Get status and 9th bit, then data */
|
||||
/* from buffer */
|
||||
uint16_t resh = UCSR1B;
|
||||
uint16_t resl = UDR1;
|
||||
uint16_t res = 0;
|
||||
|
||||
/* Filter the 9th bit, then return */
|
||||
resh = (resh >> 1) & 0x01;
|
||||
res = ((resh << 8) | resl);
|
||||
if((res == 0x180) | (res == 0x1C0)){ //button REb filter
|
||||
keys[BTN_REa].input((res & 0x1C0) == 0x1C0);
|
||||
} else if((res & 0x100) == 0x100){ //rotary filter
|
||||
vpotToChange = res & 0xEF;
|
||||
vpot_mod_state = 1;
|
||||
}
|
||||
else {
|
||||
if(vpot_mod_state & (vpotToChange < NUM_ROTARY_ENCODERS))
|
||||
{
|
||||
int8_t vpot_inc = res & 0xFF;
|
||||
if(vpot_inc){
|
||||
incRotaryEncoder(vpotToChange, vpot_inc);
|
||||
}
|
||||
vpot_mod_state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t pwrCheck()
|
||||
{
|
||||
#if !defined(SIMU) && !defined(REV0)
|
||||
if ((PING & 0b00000010) && (~PINL & 0b01000000))
|
||||
return e_power_off;
|
||||
#endif
|
||||
return e_power_on;
|
||||
}
|
||||
|
||||
void pwrOff()
|
||||
{
|
||||
#ifndef REV0
|
||||
PORTL = 0x7f;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t keyDown()
|
||||
{
|
||||
return ((~PINL) & 0x3F) || ROTENC_DOWN();
|
||||
}
|
||||
|
||||
uint8_t keyState(uint8_t index)
|
||||
{
|
||||
return keys[index].state();
|
||||
}
|
||||
|
||||
uint8_t switchState(uint8_t index)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
switch (index) {
|
||||
case SW_ELE:
|
||||
result = PINC & (1<<INP_C_ElevDR);
|
||||
break;
|
||||
|
||||
case SW_AIL:
|
||||
result = PINC & (1<<INP_C_AileDR);
|
||||
break;
|
||||
|
||||
case SW_RUD:
|
||||
result = PING & (1<<INP_G_RuddDR);
|
||||
break;
|
||||
// INP_G_ID1 INP_B_ID2
|
||||
// id0 0 1
|
||||
// id1 1 1
|
||||
// id2 1 0
|
||||
case SW_ID0:
|
||||
result = !(PING & (1<<INP_G_ID1));
|
||||
break;
|
||||
|
||||
case SW_ID1:
|
||||
result = (PING & (1<<INP_G_ID1))&& (PINB & (1<<INP_B_ID2));
|
||||
break;
|
||||
|
||||
case SW_ID2:
|
||||
result = !(PINB & (1<<INP_B_ID2));
|
||||
break;
|
||||
|
||||
case SW_GEA:
|
||||
result = PING & (1<<INP_G_Gear);
|
||||
break;
|
||||
|
||||
case SW_THR:
|
||||
result = PING & (1<<INP_G_ThrCt);
|
||||
break;
|
||||
|
||||
case SW_TRN:
|
||||
result = PINB & (1<<INP_B_Trainer);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const pm_uchar crossTrim[] PROGMEM = {
|
||||
TRIMS_GPIO_PIN_LHL,
|
||||
TRIMS_GPIO_PIN_LHR,
|
||||
TRIMS_GPIO_PIN_LVD,
|
||||
TRIMS_GPIO_PIN_LVU,
|
||||
TRIMS_GPIO_PIN_RVD,
|
||||
TRIMS_GPIO_PIN_RVU,
|
||||
TRIMS_GPIO_PIN_RHL,
|
||||
TRIMS_GPIO_PIN_RHR
|
||||
};
|
||||
|
||||
uint8_t trimDown(uint8_t idx)
|
||||
{
|
||||
uint8_t in = ~PIND;
|
||||
return (in & pgm_read_byte(crossTrim+idx));
|
||||
}
|
||||
|
||||
void readKeysAndTrims()
|
||||
{
|
||||
uint8_t index = KEY_MENU;
|
||||
|
||||
// User buttons ...
|
||||
uint8_t tin = ~PINL;
|
||||
uint8_t in;
|
||||
in = (tin & 0x0f) << 3;
|
||||
in |= (tin & 0x30) >> 3;
|
||||
for (int i=1; i<7; i++) {
|
||||
keys[index].input(in & (1<<i));
|
||||
++index;
|
||||
}
|
||||
|
||||
// Trims ...
|
||||
in = ~PINJ;
|
||||
for (int i=0; i<8; i++) {
|
||||
// INP_D_TRM_RH_UP 0 .. INP_D_TRM_LH_UP 7
|
||||
keys[index].input(in & pgm_read_byte(crossTrim+i));
|
||||
++index;
|
||||
}
|
||||
|
||||
#if defined(ROTARY_ENCODERS)
|
||||
keys[BTN_REa].input(REA_DOWN());
|
||||
keys[BTN_REb].input(REB_DOWN());
|
||||
#endif
|
||||
}
|
||||
|
||||
ISR(INT2_vect)
|
||||
{
|
||||
uint8_t input = (PIND & 0x0C);
|
||||
if (input == 0 || input == 0x0C) incRotaryEncoder(0, -1);
|
||||
}
|
||||
|
||||
ISR(INT3_vect)
|
||||
{
|
||||
uint8_t input = (PIND & 0x0C);
|
||||
if (input == 0 || input == 0x0C) incRotaryEncoder(0, +1);
|
||||
}
|
||||
|
||||
ISR(INT5_vect)
|
||||
{
|
||||
uint8_t input = (PINE & 0x60);
|
||||
if (input == 0 || input == 0x60) incRotaryEncoder(1, +1);
|
||||
}
|
||||
|
||||
ISR(INT6_vect)
|
||||
{
|
||||
uint8_t input = (PINE & 0x60);
|
||||
if (input == 0 || input == 0x60) incRotaryEncoder(1, -1);
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_GRUVIN9X_H_
|
||||
#define _BOARD_GRUVIN9X_H_
|
||||
|
||||
#include "../common/avr/board_avr.h"
|
||||
|
||||
// Board driver
|
||||
void boardInit(void);
|
||||
#define boardOff() pwrOff()
|
||||
|
||||
// Keys
|
||||
#define KEYS_GPIO_REG_MENU pinl
|
||||
#define KEYS_GPIO_PIN_MENU (1<<4)
|
||||
#define KEYS_GPIO_REG_EXIT pinl
|
||||
#define KEYS_GPIO_PIN_EXIT (1<<5)
|
||||
#define KEYS_GPIO_REG_RIGHT pinl
|
||||
#define KEYS_GPIO_PIN_RIGHT (1<<2)
|
||||
#define KEYS_GPIO_REG_LEFT pinl
|
||||
#define KEYS_GPIO_PIN_LEFT (1<<3)
|
||||
#define KEYS_GPIO_REG_UP pinl
|
||||
#define KEYS_GPIO_PIN_UP (1<<1)
|
||||
#define KEYS_GPIO_REG_DOWN pinl
|
||||
#define KEYS_GPIO_PIN_DOWN (1<<0)
|
||||
#define IS_SHIFT_KEY(index) (false)
|
||||
#define IS_SHIFT_PRESSED() (false)
|
||||
|
||||
// Trims
|
||||
#define NUM_TRIMS 4
|
||||
#define NUM_TRIMS_KEYS (NUM_TRIMS * 2)
|
||||
#define TRIMS_GPIO_REG_LHL pinj
|
||||
#define TRIMS_GPIO_REG_LVD pinj
|
||||
#define TRIMS_GPIO_REG_RVU pinj
|
||||
#define TRIMS_GPIO_REG_RHL pinj
|
||||
#define TRIMS_GPIO_REG_LHR pinj
|
||||
#define TRIMS_GPIO_REG_LVU pinj
|
||||
#define TRIMS_GPIO_REG_RVD pinj
|
||||
#define TRIMS_GPIO_REG_RHR pinj
|
||||
#define TRIMS_GPIO_PIN_LHL (1<<0)
|
||||
#define TRIMS_GPIO_PIN_LVD (1<<2)
|
||||
#define TRIMS_GPIO_PIN_RVU (1<<5)
|
||||
#define TRIMS_GPIO_PIN_RHL (1<<6)
|
||||
#define TRIMS_GPIO_PIN_LHR (1<<1)
|
||||
#define TRIMS_GPIO_PIN_LVU (1<<3)
|
||||
#define TRIMS_GPIO_PIN_RVD (1<<4)
|
||||
#define TRIMS_GPIO_PIN_RHR (1<<7)
|
||||
|
||||
#define TIMER_16KHZ_VECT TIMER2_OVF_vect
|
||||
#define COUNTER_16KHZ TCNT2
|
||||
#define TIMER_10MS_VECT TIMER2_COMPA_vect
|
||||
#define TIMER_10MS_COMPVAL OCR2A
|
||||
#define PAUSE_10MS_INTERRUPT() TIMSK2 &= ~(1<<OCIE2A)
|
||||
#define RESUME_10MS_INTERRUPT() TIMSK2 |= (1<<OCIE2A)
|
||||
#define PAUSE_PPMIN_INTERRUPT() TIMSK3 &= ~(1<<ICIE3)
|
||||
#define RESUME_PPMIN_INTERRUPT() TIMSK3 |= (1<<ICIE3)
|
||||
|
||||
#define SLAVE_MODE() (PING & (1<<INP_G_RF_POW))
|
||||
#define JACK_PPM_OUT() PORTG |= (1<<OUT_G_SIM_CTL)
|
||||
#define JACK_PPM_IN() PORTG &= ~(1<<OUT_G_SIM_CTL)
|
||||
|
||||
// SD driver
|
||||
#define BLOCK_SIZE 512 /* Block Size in Bytes */
|
||||
#define sdDone()
|
||||
#define SD_IS_HC() (0)
|
||||
#define SD_GET_SPEED() (0)
|
||||
#if !defined(SIMU)
|
||||
bool sdMounted();
|
||||
void sdMountPoll();
|
||||
void sdPoll10ms();
|
||||
#endif
|
||||
|
||||
#define speakerOn() TCCR0A |= (1 << COM0A0)
|
||||
#define speakerOff() TCCR0A &= ~(1 << COM0A0)
|
||||
|
||||
// Backlight driver
|
||||
#define OUT_C_LIGHT 0
|
||||
#define backlightEnable() PORTC |= (1<<OUT_C_LIGHT)
|
||||
#define backlightDisable() PORTC &= ~(1<<OUT_C_LIGHT)
|
||||
#define isBacklightEnabled() (PORTC & (1<<OUT_C_LIGHT))
|
||||
#define BACKLIGHT_ENABLE() backlightEnable()
|
||||
#define BACKLIGHT_DISABLE() backlightDisable()
|
||||
|
||||
#define INP_E_PPM_IN 7
|
||||
#define INP_E_ROT_ENC_1_B 6
|
||||
#define INP_E_ROT_ENC_1_A 5
|
||||
#define INP_E_USB_D_PLS 4
|
||||
#define OUT_E_BUZZER 3
|
||||
#define INP_E_USB_D_NEG 2
|
||||
#define INP_E_TELEM_RX 1
|
||||
#define OUT_E_TELEM_TX 0
|
||||
|
||||
#define OUT_D_HAPTIC 7
|
||||
#define INP_D_SPARE4 6
|
||||
#define INP_D_ROT_ENC_2_PUSH 5
|
||||
#define INP_D_ROT_ENC_1_PUSH 4
|
||||
#define OUT_D_ROT_ENC_2_B 3
|
||||
#define INP_D_ROT_ENC_2_A 2
|
||||
#define INP_D_I2C_SCL 1
|
||||
#define INP_D_I2C_SDA 0
|
||||
|
||||
#define INP_G_Gear 5
|
||||
#define INP_G_ThrCt 2
|
||||
#define OUT_G_SIM_CTL 4 //1 : phone-jack=ppm_in
|
||||
#define INP_G_ID1 3
|
||||
#define INP_G_RF_POW 1
|
||||
#define INP_G_RuddDR 0
|
||||
|
||||
#define INP_C_AileDR 7
|
||||
#define INP_C_ElevDR 6
|
||||
|
||||
#define OUT_B_Speaker 7
|
||||
#define OUT_B_PPM 6 // will be switched by TCNT1==OCR1B in hardware
|
||||
#define INP_B_Trainer 5
|
||||
#define INP_B_ID2 4
|
||||
|
||||
#if defined(VOICE)
|
||||
#define OUT_H_14DRESET 3
|
||||
#define OUT_H_14DCLK 4
|
||||
#define OUT_H_14DDATA 5
|
||||
#define INP_H_14DBUSY 6
|
||||
#endif
|
||||
|
||||
// Keys driver
|
||||
#define TRIMS_PRESSED() (~PINJ)
|
||||
#define KEYS_PRESSED() (~PINL) // used only for DBLKEYS code.
|
||||
|
||||
// LCD driver
|
||||
#define PORTA_LCD_DAT PORTA
|
||||
#define PORTC_LCD_CTRL PORTC
|
||||
#define OUT_C_LCD_E 5
|
||||
#define OUT_C_LCD_RnW 4
|
||||
#define OUT_C_LCD_A0 3
|
||||
#define OUT_C_LCD_RES 2
|
||||
#define OUT_C_LCD_CS1 1
|
||||
|
||||
// Power driver
|
||||
uint8_t pwrCheck();
|
||||
void pwrOff();
|
||||
#define UNEXPECTED_SHUTDOWN() ((mcusr & (1 << WDRF)) || g_eeGeneral.unexpectedShutdown)
|
||||
|
||||
// USB fake driver
|
||||
#define usbPlugged() false
|
||||
|
||||
// Haptic driver
|
||||
#define hapticOn() PORTD &= ~(1 << OUT_D_HAPTIC)
|
||||
#define hapticOff() PORTD |= (1 << OUT_D_HAPTIC)
|
||||
|
||||
// Rotary encoder driver
|
||||
#define REA_DOWN() (~PIND & 0x20)
|
||||
#define REB_DOWN() (~PIND & 0x10)
|
||||
#define ROTENC_DOWN() (REA_DOWN() || REB_DOWN())
|
||||
|
||||
// Buzzer driver
|
||||
#define buzzerOn() PORTE |= (1 << OUT_E_BUZZER)
|
||||
#define buzzerOff() PORTE &= ~(1 << OUT_E_BUZZER)
|
||||
|
||||
// Battery driver
|
||||
#define BATTERY_MIN 90 // 9V
|
||||
#define BATTERY_MAX 120 // 12V
|
||||
#define BATTERY_WARN 90 // 9V
|
||||
|
||||
// Analogs driver
|
||||
#define NUM_MOUSE_ANALOGS 0
|
||||
#define NUM_DUMMY_ANAS 0
|
||||
|
||||
#endif // _BOARD_GRUVIN9X_H_
|
||||
@@ -1,676 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2010 */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Only rcvr_spi(), xmit_spi(), sdPoll10mS() and some macros */
|
||||
/* are platform dependent. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "diskio.h"
|
||||
|
||||
/* Definitions for MMC/SDC command */
|
||||
#define CMD0 (0) /* GO_IDLE_STATE */
|
||||
#define CMD1 (1) /* SEND_OP_COND (MMC) */
|
||||
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
|
||||
#define CMD8 (8) /* SEND_IF_COND */
|
||||
#define CMD9 (9) /* SEND_CSD */
|
||||
#define CMD10 (10) /* SEND_CID */
|
||||
#define CMD12 (12) /* STOP_TRANSMISSION */
|
||||
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
|
||||
#define CMD16 (16) /* SET_BLOCKLEN */
|
||||
#define CMD17 (17) /* READ_SINGLE_BLOCK */
|
||||
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
|
||||
#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
|
||||
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
|
||||
#define CMD24 (24) /* WRITE_BLOCK */
|
||||
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
|
||||
#define CMD55 (55) /* APP_CMD */
|
||||
#define CMD58 (58) /* READ_OCR */
|
||||
|
||||
/* Card type flags (CardType) */
|
||||
#define CT_MMC 0x01 /* MMC ver 3 */
|
||||
#define CT_SD1 0x02 /* SD ver 1 */
|
||||
#define CT_SD2 0x04 /* SD ver 2 */
|
||||
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
|
||||
#define CT_BLOCK 0x08 /* Block addressing */
|
||||
|
||||
/* Port Controls (Platform dependent) */
|
||||
// GCC optimisation should result in a single CBI/SBI instructions here
|
||||
#if defined (CPUM2560)
|
||||
# define CS_LOW() PORTB &= ~0x01 /* MMC CS = L */
|
||||
# define CS_HIGH() PORTB |= 0x01 /* MMC CS = H */
|
||||
#else
|
||||
# define CS_LOW() PORTB &= ~0x10 /* MMC CS = L */
|
||||
# define CS_HIGH() PORTB |= 0x10 /* MMC CS = H */
|
||||
#endif
|
||||
|
||||
#define SOCKPORT PINB /* Socket contact port */
|
||||
#define SOCKWP 0x00 // not implemented /* Write protect switch */
|
||||
#define SOCKINS 0x00 // not implemented /* Card detect switch */
|
||||
|
||||
#define FCLK_SLOW() SPCR = 0x52 /* Set slow clock (100k-400k) */
|
||||
#define FCLK_FAST() SPCR = 0x50 /* Set fast clock (depends on the CSD) */
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
Module Private Functions
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
static volatile
|
||||
DSTATUS Stat = STA_NOINIT; /* Disk status */
|
||||
|
||||
volatile BYTE Timer1, Timer2; /* 100Hz decrement timer */
|
||||
|
||||
static
|
||||
BYTE CardType; /* Card type flags */
|
||||
|
||||
#if defined(SIMU)
|
||||
#define loop_mixer_until_bit_is_set loop_until_bit_is_set
|
||||
#else
|
||||
inline void checkMixer()
|
||||
{
|
||||
// TODO duplicated code ...
|
||||
uint16_t t0 = getTmr16KHz();
|
||||
int16_t delta = (nextMixerEndTime - lastMixerDuration) - t0;
|
||||
if (delta > 0 && delta < MAX_MIXER_DELTA) return;
|
||||
|
||||
nextMixerEndTime = t0 + MAX_MIXER_DELTA;
|
||||
|
||||
doMixerCalculations();
|
||||
|
||||
t0 = getTmr16KHz() - t0;
|
||||
lastMixerDuration = t0;
|
||||
if (t0 > maxMixerDuration) maxMixerDuration = t0;
|
||||
}
|
||||
|
||||
#define loop_mixer_until_bit_is_set(sfr, bit) do { checkMixer(); wdt_reset(); } while (bit_is_clear(sfr, bit))
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Transmit a byte to MMC via SPI (Platform dependent) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#define xmit_spi(dat) SPDR=(dat); loop_mixer_until_bit_is_set(SPSR,SPIF)
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Receive a byte from MMC via SPI (Platform dependent) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BYTE rcvr_spi (void)
|
||||
{
|
||||
SPDR = 0xFF;
|
||||
loop_mixer_until_bit_is_set(SPSR, SPIF);
|
||||
return SPDR;
|
||||
}
|
||||
|
||||
/* Alternative macro to receive data fast */
|
||||
#define rcvr_spi_m(dst) SPDR=0xFF; loop_mixer_until_bit_is_set(SPSR,SPIF); *(dst)=SPDR
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Wait for card ready */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int wait_ready (void) /* 1:OK, 0:Timeout */
|
||||
{
|
||||
Timer2 = 50; /* Wait for ready in timeout of 500ms (G: now 50x16ms) */
|
||||
rcvr_spi();
|
||||
do
|
||||
if (rcvr_spi() == 0xFF) return 1;
|
||||
while (Timer2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Deselect the card and release SPI bus */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
void deselect (void)
|
||||
{
|
||||
CS_HIGH();
|
||||
rcvr_spi();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Select the card and wait for ready */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int select (void) /* 1:Successful, 0:Timeout */
|
||||
{
|
||||
CS_LOW();
|
||||
if (!wait_ready()) {
|
||||
deselect();
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Power Control (Platform dependent) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* When the target system does not support socket power control, there */
|
||||
/* is nothing to do in these functions and chk_power always returns 1. */
|
||||
|
||||
static
|
||||
int power_status(void) /* Socket power state: 0=off, 1=on */
|
||||
{
|
||||
return (PORTE & 0x80) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void power_on (void)
|
||||
{
|
||||
// PORTE &= ~0x80; // Socket power on
|
||||
#ifndef SIMU
|
||||
for (Timer1 = 2; Timer1; ); // Wait for 20ms
|
||||
#endif
|
||||
//PORTB = 0b10110101; // Enable drivers
|
||||
//DDRB = 0b11000111;
|
||||
|
||||
SPCR = 0x52; // Enable SPI function in mode 0
|
||||
SPSR = 0x00; // G: was 0x01; // SPI 2x mode
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void power_off (void)
|
||||
{
|
||||
SPCR = 0; /* Disable SPI function */
|
||||
// DDRB = 0b11000000; /* Disable drivers */
|
||||
// PORTB = 0b10110000;
|
||||
|
||||
// PORTE |= 0x80; /* Socket power off */
|
||||
Stat |= STA_NOINIT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Receive a data packet from MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int rcvr_datablock (
|
||||
BYTE *buff, /* Data buffer to store received data */
|
||||
UINT btr /* Byte count (must be multiple of 4) */
|
||||
)
|
||||
{
|
||||
BYTE token;
|
||||
|
||||
|
||||
Timer1 = 20;
|
||||
do { /* Wait for data packet in timeout of 200ms */
|
||||
token = rcvr_spi();
|
||||
} while ((token == 0xFF) && Timer1);
|
||||
if(token != 0xFE) return 0; /* If not valid data token, retutn with error */
|
||||
|
||||
do { /* Receive the data block into buffer */
|
||||
rcvr_spi_m(buff++);
|
||||
rcvr_spi_m(buff++);
|
||||
rcvr_spi_m(buff++);
|
||||
rcvr_spi_m(buff++);
|
||||
} while (btr -= 4);
|
||||
rcvr_spi(); /* Discard CRC */
|
||||
rcvr_spi();
|
||||
|
||||
return 1; /* Return with success */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Send a data packet to MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int xmit_datablock (
|
||||
const BYTE *buff, /* 512 byte data block to be transmitted */
|
||||
BYTE token /* Data/Stop token */
|
||||
)
|
||||
{
|
||||
BYTE resp, wc;
|
||||
|
||||
|
||||
if (!wait_ready()) return 0;
|
||||
|
||||
xmit_spi(token); /* Xmit data token */
|
||||
if (token != 0xFD) { /* Is data token */
|
||||
wc = 0;
|
||||
do { /* Xmit the 512 byte data block to MMC */
|
||||
xmit_spi(*buff++);
|
||||
xmit_spi(*buff++);
|
||||
} while (--wc);
|
||||
xmit_spi(0xFF); /* CRC (Dummy) */
|
||||
xmit_spi(0xFF);
|
||||
resp = rcvr_spi(); /* Reveive data response */
|
||||
if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Send a command packet to MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */
|
||||
BYTE cmd, /* Command index */
|
||||
DWORD arg /* Argument */
|
||||
)
|
||||
{
|
||||
BYTE n, res;
|
||||
|
||||
|
||||
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
|
||||
cmd &= 0x7F;
|
||||
res = send_cmd(CMD55, 0);
|
||||
if (res > 1) return res;
|
||||
}
|
||||
|
||||
/* Select the card and wait for ready */
|
||||
deselect();
|
||||
if (!select()) return 0xFF;
|
||||
|
||||
/* Send command packet */
|
||||
xmit_spi(0x40 | cmd); /* Start + Command index */
|
||||
xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
|
||||
xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
|
||||
xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
|
||||
xmit_spi((BYTE)arg); /* Argument[7..0] */
|
||||
n = 0x01; /* Dummy CRC + Stop */
|
||||
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
|
||||
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
|
||||
xmit_spi(n);
|
||||
|
||||
/* Receive command response */
|
||||
if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */
|
||||
n = 10; /* Wait for a valid response in timeout of 10 attempts */
|
||||
do
|
||||
res = rcvr_spi();
|
||||
while ((res & 0x80) && --n);
|
||||
|
||||
return res; /* Return with the response value */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
Public Functions
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Initialize Disk Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE drv /* Physical drive nmuber (0) */
|
||||
)
|
||||
{
|
||||
BYTE n, cmd, ty, ocr[4];
|
||||
|
||||
|
||||
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||
if (Stat & STA_NODISK) return Stat; /* No card in the socket */
|
||||
|
||||
power_on(); /* Force socket power on */
|
||||
FCLK_SLOW();
|
||||
for (n = 10; n; n--) rcvr_spi(); /* 80 dummy clocks */
|
||||
|
||||
ty = 0;
|
||||
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
|
||||
Timer1 = 100; /* Initialization timeout of 1000 msec */
|
||||
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); /* Get trailing return value of R7 resp */
|
||||
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
|
||||
while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */
|
||||
if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
|
||||
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */
|
||||
}
|
||||
}
|
||||
} else { /* SDv1 or MMCv3 */
|
||||
if (send_cmd(ACMD41, 0) <= 1) {
|
||||
ty = CT_SD1; cmd = ACMD41; /* SDv1 */
|
||||
} else {
|
||||
ty = CT_MMC; cmd = CMD1; /* MMCv3 */
|
||||
}
|
||||
while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */
|
||||
if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
|
||||
ty = 0;
|
||||
}
|
||||
}
|
||||
CardType = ty;
|
||||
deselect();
|
||||
|
||||
if (ty) { /* Initialization succeded */
|
||||
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
|
||||
FCLK_FAST();
|
||||
} else { /* Initialization failed */
|
||||
power_off();
|
||||
}
|
||||
|
||||
return Stat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Disk Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE drv /* Physical drive number (0) */
|
||||
)
|
||||
{
|
||||
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||
return Stat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
BYTE *buff, /* Pointer to the data buffer to store read data */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
UINT count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
|
||||
|
||||
if (count == 1) { /* Single block read */
|
||||
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
|
||||
&& rcvr_datablock(buff, 512))
|
||||
count = 0;
|
||||
}
|
||||
else { /* Multiple block read */
|
||||
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!rcvr_datablock(buff, 512)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
|
||||
}
|
||||
}
|
||||
deselect();
|
||||
|
||||
return count ? RES_ERROR : RES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_write (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
const BYTE *buff, /* Pointer to the data to be written */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
UINT count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
if (Stat & STA_PROTECT) return RES_WRPRT;
|
||||
|
||||
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
|
||||
|
||||
if (count == 1) { /* Single block write */
|
||||
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
|
||||
&& xmit_datablock(buff, 0xFE))
|
||||
count = 0;
|
||||
}
|
||||
else { /* Multiple block write */
|
||||
if (CardType & CT_SDC) send_cmd(ACMD23, count);
|
||||
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!xmit_datablock(buff, 0xFC)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
deselect();
|
||||
|
||||
return count ? RES_ERROR : RES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
BYTE ctrl, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
DRESULT res;
|
||||
BYTE n, csd[16], *ptr = (BYTE*)buff;
|
||||
WORD csize;
|
||||
|
||||
|
||||
if (drv) return RES_PARERR;
|
||||
|
||||
res = RES_ERROR;
|
||||
|
||||
if (ctrl == CTRL_POWER) {
|
||||
switch (ptr[0]) {
|
||||
case 0: /* Sub control code (POWER_OFF) */
|
||||
power_off(); /* Power off */
|
||||
res = RES_OK;
|
||||
break;
|
||||
case 1: /* Sub control code (POWER_GET) */
|
||||
ptr[1] = (BYTE)power_status();
|
||||
res = RES_OK;
|
||||
break;
|
||||
default :
|
||||
res = RES_PARERR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
switch (ctrl) {
|
||||
case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
|
||||
if (select()) {
|
||||
deselect();
|
||||
res = RES_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
||||
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
|
||||
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
|
||||
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
|
||||
*(DWORD*)buff = (DWORD)csize << 10;
|
||||
} else { /* SDC ver 1.XX or MMC*/
|
||||
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
|
||||
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
|
||||
*(DWORD*)buff = (DWORD)csize << (n - 9);
|
||||
}
|
||||
res = RES_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
|
||||
*(WORD*)buff = 512;
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
|
||||
if (CardType & CT_SD2) { /* SDv2? */
|
||||
if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
|
||||
rcvr_spi();
|
||||
if (rcvr_datablock(csd, 16)) { /* Read partial block */
|
||||
for (n = 64 - 16; n; n--) rcvr_spi(); /* Purge trailing data */
|
||||
*(DWORD*)buff = 16UL << (csd[10] >> 4);
|
||||
res = RES_OK;
|
||||
}
|
||||
}
|
||||
} else { /* SDv1 or MMCv3 */
|
||||
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
|
||||
if (CardType & CT_SD1) { /* SDv1 */
|
||||
*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
|
||||
} else { /* MMCv3 */
|
||||
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
|
||||
}
|
||||
res = RES_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC_GET_TYPE : /* Get card type flags (1 byte) */
|
||||
*ptr = CardType;
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */
|
||||
if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
|
||||
&& rcvr_datablock(ptr, 16))
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */
|
||||
if (send_cmd(CMD10, 0) == 0 /* READ_CID */
|
||||
&& rcvr_datablock(ptr, 16))
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
|
||||
if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
|
||||
for (n = 4; n; n--) *ptr++ = rcvr_spi();
|
||||
res = RES_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */
|
||||
if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
|
||||
rcvr_spi();
|
||||
if (rcvr_datablock(ptr, 64))
|
||||
res = RES_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
res = RES_PARERR;
|
||||
}
|
||||
|
||||
deselect();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Device Timer Interrupt Procedure */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* This function must be called in period of 10ms */
|
||||
|
||||
void sdPoll10ms()
|
||||
{
|
||||
BYTE s;
|
||||
|
||||
/*
|
||||
n = Timer1; // 100Hz decrement timer
|
||||
if (n) Timer1 = --n;
|
||||
n = Timer2;
|
||||
if (n) Timer2 = --n;
|
||||
*/
|
||||
if (Timer1) Timer1--;
|
||||
if (Timer2) Timer2--;
|
||||
|
||||
s = Stat;
|
||||
|
||||
/* G: Not implemented
|
||||
if (SOCKWP) // Write protected
|
||||
s |= STA_PROTECT;
|
||||
else // Write enabled
|
||||
s &= ~STA_PROTECT;
|
||||
if (SOCKINS) // Card inserted
|
||||
s &= ~STA_NODISK;
|
||||
else // Socket empty
|
||||
s |= (STA_NODISK | STA_NOINIT);
|
||||
*/
|
||||
s &= ~STA_NODISK;
|
||||
s &= ~STA_PROTECT;
|
||||
|
||||
Stat = s;
|
||||
}
|
||||
|
||||
#if !defined(SIMU)
|
||||
bool sdMounted()
|
||||
{
|
||||
return g_FATFS_Obj.fs_type != 0;
|
||||
}
|
||||
|
||||
void sdMountPoll()
|
||||
{
|
||||
static uint8_t mountTimer;
|
||||
if (mountTimer-- == 0) {
|
||||
mountTimer = 100;
|
||||
if (!sdMounted()) {
|
||||
f_mount(&g_FATFS_Obj, "", 1);
|
||||
f_chdir(ROOT_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
FATFS g_FATFS_Obj;
|
||||
@@ -1,36 +0,0 @@
|
||||
The ATmega2561 uses quite different bit assignment for its option fuses
|
||||
|
||||
|
||||
Fuse defaults for ATmega64A
|
||||
|
||||
Default values for ATmega64 are:
|
||||
hfuse = 0b10011001 (0x99)
|
||||
lfuse = 0b11100001 (0xE1)
|
||||
efuse = 0b11111101 (0xFD)
|
||||
|
||||
Preferred values for ATmega64A are:
|
||||
hfuse = 0x11
|
||||
lfuse = 0x1F
|
||||
efuse = 0xff
|
||||
|
||||
... which includes EESAVE feature, so that the EEPROM model data does NOT get
|
||||
erased during chip erase prior to re-programming ... respectively.
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
Fuse defaults for ATmega2560/1 are:
|
||||
|
||||
hfuse = 0b10011001 (0x99)
|
||||
lfuse = 0b01100010 (0x62)
|
||||
efuse = 0b11111111 (0xFF)
|
||||
|
||||
The bit assignments ae quite different from the AT'64A in all cases.
|
||||
|
||||
Preferred vale es for ATmega2560/1 are:
|
||||
hfuse = 0b10011001 (0x11) [OCD enabled, JTAG enabled, WDT disabled :(,
|
||||
EESAVE enabled, BOOT at 0x0000]
|
||||
lfuse = 0b01101110 (0xd7) [CKDIV8 disabled, CKOUT disabled,
|
||||
Full Swing Xtal Osc, 16K CK + 0ms reset,
|
||||
BOD enabled]
|
||||
efuse = 0b11111111 (0xfc) [ Brown out detector (BOD) = 4.3V ]
|
||||
|
||||
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* RTC controls */
|
||||
|
||||
#include "opentx.h"
|
||||
#include "FatFs/integer.h"
|
||||
|
||||
typedef struct {
|
||||
WORD year; /* 2000..2099 */
|
||||
BYTE month; /* 1..12 */
|
||||
BYTE mday; /* 1.. 31 */
|
||||
BYTE wday; /* 1..7 */
|
||||
BYTE hour; /* 0..23 */
|
||||
BYTE min; /* 0..59 */
|
||||
BYTE sec; /* 0..59 */
|
||||
} RTC;
|
||||
|
||||
#define SCL_LOW() DDRD |= 0x01 /* SCL = LOW */
|
||||
#define SCL_HIGH() DDRD &= ~0x01 /* SCL = High-Z */
|
||||
#define SCL_VAL ((PIND & 0x01) ? 1 : 0) /* SCL input level */
|
||||
#define SDA_LOW() DDRD |= 0x02 /* SDA = LOW */
|
||||
#define SDA_HIGH() DDRD &= ~0x02 /* SDA = High-Z */
|
||||
#define SDA_VAL ((PIND & 0x02) ? 1 : 0) /* SDA input level */
|
||||
|
||||
/*-------------------------------------------------*/
|
||||
/* I2C bus protocol */
|
||||
|
||||
static
|
||||
void iic_delay (void)
|
||||
{
|
||||
#ifndef SIMU
|
||||
for (int n = 4; n; n--) PINB;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Generate start condition on the IIC bus */
|
||||
static
|
||||
void iic_start (void)
|
||||
{
|
||||
SDA_HIGH();
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
iic_delay();
|
||||
SDA_LOW();
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
iic_delay();
|
||||
}
|
||||
|
||||
|
||||
/* Generate stop condition on the IIC bus */
|
||||
static
|
||||
void iic_stop (void)
|
||||
{
|
||||
SDA_LOW();
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
iic_delay();
|
||||
SDA_HIGH();
|
||||
iic_delay();
|
||||
}
|
||||
|
||||
|
||||
/* Send a byte to the IIC bus */
|
||||
static
|
||||
int iic_send (BYTE dat)
|
||||
{
|
||||
BYTE b = 0x80;
|
||||
int ack;
|
||||
|
||||
|
||||
do {
|
||||
if (dat & b) { /* SDA = Z/L */
|
||||
SDA_HIGH();
|
||||
} else {
|
||||
SDA_LOW();
|
||||
}
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
iic_delay();
|
||||
} while (b >>= 1);
|
||||
SDA_HIGH();
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
ack = SDA_VAL ? 0 : 1; /* Sample ACK */
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
iic_delay();
|
||||
return ack;
|
||||
}
|
||||
|
||||
|
||||
/* Receive a byte from the IIC bus */
|
||||
static
|
||||
BYTE iic_rcvr (int ack)
|
||||
{
|
||||
UINT d = 1;
|
||||
|
||||
|
||||
do {
|
||||
d <<= 1;
|
||||
SCL_HIGH();
|
||||
if (SDA_VAL) d++;
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
iic_delay();
|
||||
} while (d < 0x100);
|
||||
if (ack) { /* SDA = ACK */
|
||||
SDA_LOW();
|
||||
} else {
|
||||
SDA_HIGH();
|
||||
}
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
SDA_HIGH();
|
||||
iic_delay();
|
||||
|
||||
return (BYTE)d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------*/
|
||||
/* I2C block read/write controls */
|
||||
|
||||
|
||||
int iic_read (
|
||||
BYTE dev, /* Device address */
|
||||
UINT adr, /* Read start address */
|
||||
UINT cnt, /* Read byte count */
|
||||
BYTE *buff /* Read data buffer */
|
||||
)
|
||||
{
|
||||
BYTE *rbuff = buff;
|
||||
int n;
|
||||
|
||||
|
||||
if (!cnt) return 0;
|
||||
|
||||
n = 10;
|
||||
do { /* Select device */
|
||||
iic_start();
|
||||
} while (!iic_send(dev) && --n);
|
||||
if (n) {
|
||||
if (iic_send((BYTE)adr)) { /* Set start address */
|
||||
iic_start(); /* Reselect device in read mode */
|
||||
if (iic_send(dev | 1)) {
|
||||
do { /* Receive data */
|
||||
cnt--;
|
||||
*rbuff++ = iic_rcvr(cnt ? 1 : 0);
|
||||
} while (cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iic_stop(); /* Deselect device */
|
||||
|
||||
return cnt ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int iic_write (
|
||||
BYTE dev, /* Device address */
|
||||
UINT adr, /* Write start address */
|
||||
UINT cnt, /* Write byte count */
|
||||
const BYTE *buff /* Data to be written */
|
||||
)
|
||||
{
|
||||
const BYTE *wbuff = buff;
|
||||
int n;
|
||||
|
||||
|
||||
if (!cnt) return 0;
|
||||
|
||||
n = 10;
|
||||
do { /* Select device */
|
||||
iic_start();
|
||||
} while (!iic_send(dev) && --n);
|
||||
if (n) {
|
||||
if (iic_send((BYTE)adr)) { /* Set start address */
|
||||
do { /* Send data */
|
||||
if (!iic_send(*wbuff++)) break;
|
||||
} while (--cnt);
|
||||
}
|
||||
}
|
||||
|
||||
iic_stop(); /* Deselect device */
|
||||
|
||||
return cnt ? 0 : 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------*/
|
||||
/* RTC functions */
|
||||
|
||||
int g9x_rtcGetTime (RTC *rtc)
|
||||
{
|
||||
BYTE buf[8];
|
||||
|
||||
if (!iic_read(0xD0, 0, 7, buf)) return 0;
|
||||
|
||||
rtc->sec = (buf[0] & 0x0F) + ((buf[0] >> 4) & 7) * 10;
|
||||
rtc->min = (buf[1] & 0x0F) + (buf[1] >> 4) * 10;
|
||||
rtc->hour = (buf[2] & 0x0F) + ((buf[2] >> 4) & 3) * 10;
|
||||
rtc->wday = (buf[2] & 0x07);
|
||||
rtc->mday = (buf[4] & 0x0F) + ((buf[4] >> 4) & 3) * 10;
|
||||
rtc->month = (buf[5] & 0x0F) + ((buf[5] >> 4) & 1) * 10;
|
||||
rtc->year = 2000 + (buf[6] & 0x0F) + (buf[6] >> 4) * 10;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int g9x_rtcSetTime (const RTC *rtc)
|
||||
{
|
||||
BYTE buf[8];
|
||||
|
||||
buf[0] = rtc->sec / 10 * 16 + rtc->sec % 10;
|
||||
buf[1] = rtc->min / 10 * 16 + rtc->min % 10;
|
||||
buf[2] = rtc->hour / 10 * 16 + rtc->hour % 10;
|
||||
buf[3] = rtc->wday & 7;
|
||||
buf[4] = rtc->mday / 10 * 16 + rtc->mday % 10;
|
||||
buf[5] = rtc->month / 10 * 16 + rtc->month % 10;
|
||||
buf[6] = (rtc->year - 2000) / 10 * 16 + (rtc->year - 2000) % 10;
|
||||
return iic_write(0xD0, 0, 7, buf);
|
||||
}
|
||||
|
||||
void rtcGetTime(struct gtm * utm)
|
||||
{
|
||||
RTC rtc = {0,0,0,0,0,0,0};
|
||||
|
||||
g9x_rtcGetTime(&rtc);
|
||||
|
||||
utm->tm_year = rtc.year - TM_YEAR_BASE;
|
||||
utm->tm_mon = rtc.month - 1;
|
||||
utm->tm_mday = rtc.mday;
|
||||
utm->tm_hour = rtc.hour;
|
||||
utm->tm_min = rtc.min;
|
||||
utm->tm_sec = rtc.sec;
|
||||
utm->tm_wday = rtc.wday - 1;
|
||||
}
|
||||
|
||||
void rtcSetTime(const struct gtm * t)
|
||||
{
|
||||
g_ms100 = 0; // start of next second begins now
|
||||
|
||||
RTC rtc;
|
||||
rtc.year = t->tm_year + TM_YEAR_BASE;
|
||||
rtc.month = t->tm_mon + 1;
|
||||
rtc.mday = t->tm_mday;
|
||||
rtc.hour = t->tm_hour;
|
||||
rtc.min = t->tm_min;
|
||||
rtc.sec = t->tm_sec;
|
||||
rtc.wday = t->tm_wday + 1;
|
||||
g9x_rtcSetTime(&rtc);
|
||||
}
|
||||
|
||||
void rtcInit (void)
|
||||
{
|
||||
BYTE buf[8]; /* RTC R/W buffer */
|
||||
UINT adr;
|
||||
|
||||
|
||||
/* Read RTC registers */
|
||||
if (!iic_read(0xD0, 0, 8, buf)) return; /* IIC error */
|
||||
|
||||
if (buf[7] & 0x20) { /* When data has been volatiled, set default time */
|
||||
/* Clear nv-ram. Reg[8..63] */
|
||||
memset(buf, 0, 8);
|
||||
for (adr = 8; adr < 64; adr += 8)
|
||||
iic_write(0x0D, adr, 8, buf);
|
||||
/* Reset time to Jan 1, '08. Reg[0..7] */
|
||||
buf[4] = 1; buf[5] = 1; buf[6] = 8;
|
||||
iic_write(0x0D, 0, 8, buf);
|
||||
}
|
||||
|
||||
struct gtm utm;
|
||||
rtcGetTime(&utm);
|
||||
g_rtcTime = gmktime(&utm);
|
||||
}
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Cam: I did think about implimenting this with an array for the timing durations
|
||||
like the original bit bang DSM2 code was done but that meant another array
|
||||
on top of the playlist one, therefore more memory waisted, and because
|
||||
the playlist must be executed one after another it would mean putting
|
||||
the code to fill the array in the interrupt (This would be unlike the
|
||||
old DSM2 code) which seemed to much for the interrupt.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
// Start and stop bits need to be 2ms in duration. Start bit is low, stop bit is high
|
||||
#define SOMOSSBIT 5 //The 2ms of a stop/start bit
|
||||
#define SOMOSTOP 48 //This is the needed 2ms (4) + 20ms (40) to allow for the
|
||||
//point at which the busy flag is checkable + 2ms for saftey (4)
|
||||
#define SOMOSTART 60 //This is the needed 2ms (4) + 2ms (4) for safety + 26ms (52) for the
|
||||
//undocumented delay that must exist between playbacks.
|
||||
#define SOMOBUSY (PINH & 0x40) /* SOMO14D Busy flag */
|
||||
#define SOMOCLK (PINH & 0x10) /* SOMO14D CLK */
|
||||
|
||||
#define QUEUE_LENGTH 10
|
||||
uint16_t somo14playlist[QUEUE_LENGTH] = {0};
|
||||
uint16_t somo14command = 0;
|
||||
uint8_t somo14RIdx = 0;
|
||||
volatile uint8_t somo14WIdx = 0;
|
||||
|
||||
#ifdef SIMU
|
||||
#define BUSY busy
|
||||
#else
|
||||
#define BUSY
|
||||
#endif
|
||||
|
||||
NOINLINE uint8_t SomoWakeup()
|
||||
{
|
||||
static uint16_t somo14_current;
|
||||
static uint8_t i = 0;
|
||||
static uint8_t busy = 0; // debugging make BOOL when done
|
||||
static uint8_t startstop = SOMOSSBIT; // Only the first playback can have this short delay
|
||||
|
||||
// printf("startstop=%d i=%d\n", startstop, i); fflush(stdout);
|
||||
|
||||
// Send no data unless we are either not busy or it's a command
|
||||
|
||||
// Only when stop bit is sent do we increment read pointer
|
||||
// This will happen before the SOMO14D busy flag gets set
|
||||
// Busy flag happens 20ms after the last data is clocked in
|
||||
if (i==0 && !busy) {
|
||||
if (somo14command) { // Allow a command to be send even if the SOMO is busy, i.e. STOP or PAUSE
|
||||
somo14_current = somo14command;
|
||||
somo14command = 0;
|
||||
busy = 1;
|
||||
}
|
||||
else if (!SOMOBUSY) {
|
||||
if (somo14RIdx == somo14WIdx) {
|
||||
return 1;
|
||||
}
|
||||
somo14_current = somo14playlist[somo14RIdx];
|
||||
somo14RIdx = (somo14RIdx + 1) % QUEUE_LENGTH;
|
||||
busy = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Start and stop bits
|
||||
if (busy && startstop) {
|
||||
// Start bit
|
||||
if (i==0) {
|
||||
if (startstop < SOMOSSBIT) { // This stretches the time before we start sending data to allow for the
|
||||
// undocumented delay that must exist between playbacks. Unfortunately the
|
||||
// device isn't ready even though the busy flag says it is.
|
||||
PORTH &= ~(1<<OUT_H_14DCLK); // Start Bit, CLK low for 2ms
|
||||
}
|
||||
startstop--;
|
||||
return 0;
|
||||
}
|
||||
// Stop bit
|
||||
if (i==16) {
|
||||
PORTH &= ~(1<<OUT_H_14DDATA); // Data low
|
||||
PORTH |= (1<<OUT_H_14DCLK); // Stop Bit, CLK high for 2ms
|
||||
startstop--;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// After stop bit is sent
|
||||
// we are done sending so prepair for next
|
||||
if (i==16 && !startstop) {
|
||||
// Cam, here I think there is a bug (if we send a "command") somo14RPtr++;
|
||||
i=0;
|
||||
busy=0;
|
||||
startstop = SOMOSTART;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send the data
|
||||
if (i<16 && busy) {
|
||||
if (!SOMOCLK) { // Only change data when the CLK is low
|
||||
startstop =SOMOSTOP;
|
||||
if (somo14_current & 0x8000) {
|
||||
PORTH |= (1<<OUT_H_14DDATA); // Data high
|
||||
}
|
||||
somo14_current = (somo14_current<<1);
|
||||
i++;
|
||||
// Data setup delay
|
||||
_delay_us(1);
|
||||
PORTH |= (1<<OUT_H_14DCLK); // CLK high
|
||||
}
|
||||
|
||||
else { // Don't alter after sending last bit in preparation for sending stop bit
|
||||
PORTH &= ~(1<<OUT_H_14DCLK); // CLK low
|
||||
PORTH &= ~(1<<OUT_H_14DDATA); // Data low
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef SIMU
|
||||
ISR(TIMER4_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)
|
||||
{OCR4A=0x1f4; reset_dly--; PORTH &= ~(1<<OUT_H_14DRESET);} // CLK low
|
||||
else if (reset_pause)
|
||||
{OCR4A=0x1f4; reset_pause--; PORTH |= (1<<OUT_H_14DRESET);} // RESET high
|
||||
else
|
||||
{
|
||||
OCR4A = 0x7d; // another 0.5ms
|
||||
TIMSK4 &= ~(1<<OCIE4A); // stop reentrance
|
||||
sei();
|
||||
uint8_t finished = SomoWakeup();
|
||||
cli();
|
||||
if (!finished) TIMSK4 |= (1<<OCIE4A);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void pushPrompt(uint16_t prompt)
|
||||
{
|
||||
/* TODO id */
|
||||
somo14playlist[somo14WIdx] = prompt;
|
||||
somo14WIdx = (somo14WIdx + 1) % QUEUE_LENGTH;
|
||||
cli();
|
||||
TIMSK4 |= (1<<OCIE4A);
|
||||
sei();
|
||||
}
|
||||
|
||||
bool isPlaying()
|
||||
{
|
||||
/* TODO id */
|
||||
#if defined(SIMU)
|
||||
return false;
|
||||
#else
|
||||
return TIMSK4 & (1<<OCIE4A);
|
||||
#endif
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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 bool 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)
|
||||
@@ -1,8 +0,0 @@
|
||||
MEGA2560 board
|
||||
|
||||
======================= DESCRIPTION =======================
|
||||
DIY radio wih :
|
||||
- Arduino MEGA2560 or compatible
|
||||
- Gruvin9x features (soft-off, SD-Card, RTC, haptic, voice, rotary encoders)
|
||||
- LCD 128x64 8 bits parallel mode
|
||||
- home made case
|
||||
@@ -1,23 +0,0 @@
|
||||
option(PWRMANAGE "Pwr Manage" OFF)
|
||||
option(SDCARD "SD card support" OFF)
|
||||
option(ROTENC_DIV2 "Rotary encoder resolution/2" OFF)
|
||||
set(ARCH AVR)
|
||||
set(MCU atmega2560)
|
||||
string(TOLOWER ${PCB} FLAVOUR)
|
||||
set(EEPROM EEPROM_RLC)
|
||||
add_definitions(-DEEPROM_VARIANT=0)
|
||||
set(GUI_DIR 128x64)
|
||||
set(TARGET_DIR mega2560)
|
||||
set(FIRMWARE_DEPENDENCIES ${FIRMWARE_DEPENDENCIES} 9x_bitmaps)
|
||||
add_definitions(-DPCB${PCB} -DCPUM2560 -DROTARY_ENCODERS=2)
|
||||
set(TARGET_SRC ${TARGET_SRC} board.cpp)
|
||||
set(GUI_SRC
|
||||
${GUI_SRC}
|
||||
model_inputs_mixes.cpp
|
||||
radio_diagkeys.cpp
|
||||
radio_diaganas.cpp
|
||||
)
|
||||
set(FIRMWARE_SRC ${FIRMWARE_SRC} targets/9x/lcd_driver.cpp)
|
||||
if(PWRMANAGE)
|
||||
add_definitions(-DPWRMANAGE)
|
||||
endif()
|
||||
@@ -1,257 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "i2c_driver.h"
|
||||
|
||||
void boardInit()
|
||||
{
|
||||
#if !defined(SIMU)
|
||||
// Set up I/O port data directions and initial states (unused pin setting : input, pull-up on)
|
||||
DDRA = 0b11111111; PORTA = 0b00000000; // LCD data
|
||||
DDRB = 0b01100111; PORTB = 0b10111111; // 7:VoiceBusy, 6:PPM_OUT, 5:SimCTRL, 4:Unused, SDCARD[3:MISO 2:MOSI 1:SCK 0:CS]
|
||||
DDRC = 0b11111100; PORTC = 0b00000011; // 7-3:LCD, 2:BackLight, 1:ID2_SW, 0:ID1_SW
|
||||
DDRD = 0b00000000; PORTD = 0b11111111; // 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 = 0b00001010; PORTE = 0b01110100; // 7:PPM_IN, 6:N/A, 5:RENC1_B, 4:RENC1_A, 3:VoiceData, 2:N/A, 1:TELEM_TX, 0:TELEM_RX
|
||||
DDRF = 0b00000000; PORTF = 0b11111111; // 7-0:Trim switch inputs
|
||||
DDRG = 0b00100000; PORTG = 0b11011111; // 7:N/A, 6:N/A, 5:VoiceClock, 4:N/A, 3:N/A, 2:TCut_SW, 1:Gear_SW, 0: RudDr_SW
|
||||
#if defined(DEBUG)
|
||||
DDRH = 0b01011011; PORTH = 0b11110100; // 7:N/A, 6:RF_Activated, 5:DSC_Activated, 4:Hold_Power, 3:Speaker, 2:N/A, 1:VoiceReset, 0:Haptic
|
||||
#else
|
||||
DDRH = 0b00011011; PORTH = 0b11110100; // 7:N/A, 6:RF_Activated, 5:DSC_Activated, 4:Hold_Power, 3:Speaker, 2:N/A, 1:VoiceReset, 0:Haptic
|
||||
#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
|
||||
DDRK = 0b00000000; PORTK = 0b00000000; // Analogic input (no pull-ups)
|
||||
DDRL = 0b00000000; PORTL = 0b11111111; // 7:TRN_SW 6:EleDR_SW, 5:ESC, 4:MENU 3:Keyb_Left, 2:Keyb_Right, 1:Keyb_Up, 0:Keyb_Down
|
||||
|
||||
adcInit();
|
||||
|
||||
/**** Set up timer/counter 0 ****/
|
||||
// TCNT0 10ms = 16MHz/1024/156(.25) periodic timer (100ms interval)
|
||||
// cycles at 9.984ms but includes 1:4 duty cycle correction to /157 to average at 10.0ms
|
||||
TCCR2B = (0b111 << CS20); // Norm mode, clk/1024 (differs from ATmega64 chip)
|
||||
OCR2A = 156;
|
||||
TIMSK2 |= (1<<OCIE2A) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts
|
||||
|
||||
#if defined(AUDIO)
|
||||
// TIMER4 set into CTC mode, prescaler 16MHz/64=250 kHz
|
||||
// Used for audio tone generation
|
||||
TCCR4B = (0b10<<WGM42) | (0b011 << CS40);
|
||||
TCCR4A = 0x00;
|
||||
#endif
|
||||
|
||||
#if defined(VOICE_WTV20)
|
||||
// Voice set-up with TIMER5
|
||||
OCR5A = 0x1F4; //2ms
|
||||
TCCR5B = (1 << WGM52) | (0b011 << CS50); // CTC OCR5A
|
||||
TIMSK5 |= (1<<OCIE5A); // Start the interrupt so the unit reset can occur
|
||||
#endif
|
||||
|
||||
#if defined(VOICE_JQ6500)
|
||||
// Voice set-up with TIMER5
|
||||
JQ6500_Serial_on; // Idle state (1)
|
||||
OCR5A = 0x19; // 0x1A=104µs needed for the 9600Bps serial command
|
||||
TCCR5B = (1 << WGM52) | (0b011 << CS50); // CTC OCR5A
|
||||
#endif
|
||||
|
||||
/* Rotary encoder interrupt set-up */
|
||||
EIMSK = 0; // disable ALL external interrupts.
|
||||
// encoder 1
|
||||
EICRB = (1<<ISC50) | (1<<ISC40); // 01 = interrupt on any edge
|
||||
EIFR = (3<<INTF4); // clear the int. flag in case it got set when changing modes
|
||||
// encoder 2
|
||||
EICRA = (1<<ISC30) | (1<<ISC20);
|
||||
EIFR = (3<<INTF2);
|
||||
EIMSK = (3<<INT4) | (3<<INT2); // enable the two rot. enc. ext. int. pairs.
|
||||
|
||||
#if defined(RTCLOCK)
|
||||
i2c_init(); // hardware I2C init
|
||||
#endif
|
||||
|
||||
#endif // !SIMU
|
||||
}
|
||||
|
||||
|
||||
uint8_t pwrCheck()
|
||||
{
|
||||
#if !defined(SIMU)
|
||||
if ((~PINH & 0b00100000) && (~PINH & 0b01000000))
|
||||
return e_power_off;
|
||||
#endif
|
||||
return e_power_on;
|
||||
}
|
||||
|
||||
void pwrOff()
|
||||
{
|
||||
PORTH &= ~0x10; // PortH-4 set to 0
|
||||
}
|
||||
|
||||
uint8_t keyDown()
|
||||
{
|
||||
return ((~PINL) & 0x3F) || ROTENC_DOWN();
|
||||
}
|
||||
|
||||
uint8_t keyState(uint8_t index)
|
||||
{
|
||||
return keys[index].state();
|
||||
}
|
||||
|
||||
uint8_t switchState(uint8_t index)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
switch (index) {
|
||||
case SW_ELE:
|
||||
result = !(PINL & (1<<INP_L_ElevDR));
|
||||
break;
|
||||
|
||||
case SW_AIL:
|
||||
result = !(PIND & (1<<INP_D_AileDR));
|
||||
break;
|
||||
|
||||
case SW_RUD:
|
||||
result = !(PING & (1<<INP_G_RuddDR));
|
||||
break;
|
||||
|
||||
// INP_C_ID1 INP_C_ID2
|
||||
// ID0 0 1
|
||||
// ID1 1 1
|
||||
// ID2 1 0
|
||||
case SW_ID0:
|
||||
result = !(PINC & (1<<INP_C_ID1));
|
||||
break;
|
||||
|
||||
case SW_ID1:
|
||||
result = (PINC & (1<<INP_C_ID1))&& (PINC & (1<<INP_C_ID2));
|
||||
break;
|
||||
|
||||
case SW_ID2:
|
||||
result = !(PINC & (1<<INP_C_ID2));
|
||||
break;
|
||||
|
||||
case SW_GEA:
|
||||
result = !(PING & (1<<INP_G_Gear));
|
||||
break;
|
||||
|
||||
case SW_THR:
|
||||
result = !(PING & (1<<INP_G_ThrCt));
|
||||
break;
|
||||
|
||||
case SW_TRN:
|
||||
result = !(PINL & (1<<INP_L_Trainer));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Trim switches
|
||||
static const pm_uchar crossTrim[] PROGMEM = {
|
||||
TRIMS_GPIO_PIN_LHL,
|
||||
TRIMS_GPIO_PIN_LHR,
|
||||
TRIMS_GPIO_PIN_LVD,
|
||||
TRIMS_GPIO_PIN_LVU,
|
||||
TRIMS_GPIO_PIN_RVD,
|
||||
TRIMS_GPIO_PIN_RVU,
|
||||
TRIMS_GPIO_PIN_RHL,
|
||||
TRIMS_GPIO_PIN_RHR
|
||||
};
|
||||
|
||||
uint8_t trimDown(uint8_t idx)
|
||||
{
|
||||
uint8_t in = ~PINF; //was PIND
|
||||
return (in & pgm_read_byte(crossTrim+idx));
|
||||
}
|
||||
|
||||
void readKeysAndTrims()
|
||||
{
|
||||
uint8_t index = KEY_MENU;
|
||||
|
||||
keys[BTN_REa].input(~PINJ & 0x01);
|
||||
keys[BTN_REb].input(~PINJ & 0x02);
|
||||
|
||||
uint8_t tin = ~PINL;
|
||||
uint8_t in;
|
||||
in = (tin & 0x0f) << 3;
|
||||
in |= (tin & 0x30) >> 3;
|
||||
|
||||
for (int i=1; i<7; i++) {
|
||||
keys[index].input(in & (1<<i));
|
||||
++index;
|
||||
}
|
||||
|
||||
// Trims
|
||||
in = ~PINF;
|
||||
for (int i=0; i<8; i++) {
|
||||
// INP_D_TRM_RH_UP 0 .. INP_D_TRM_LH_UP 7
|
||||
keys[index].input(in & pgm_read_byte(crossTrim+i));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
// Rotary encoders increment/decrement (0 = rotary 1, 1 = rotary 2)
|
||||
ISR(INT4_vect) // Arduino2560 IO02 (portE pin4)
|
||||
{
|
||||
uint8_t input = (PINE & 0x30);
|
||||
#if defined (ROTENC_DIV2)// Rotenc resolution/2
|
||||
if (input == 0) incRotaryEncoder(0, -1);
|
||||
#else
|
||||
if (input == 0 || input == 0x30) incRotaryEncoder(0, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
ISR(INT5_vect) // Arduino2560 IO03 (portE pin5)
|
||||
{
|
||||
uint8_t input = (PINE & 0x30);
|
||||
#if defined (ROTENC_DIV2)// Rotenc resolution/2
|
||||
if (input == 0) incRotaryEncoder(0, +1);
|
||||
#else
|
||||
if (input == 0 || input == 0x30) incRotaryEncoder(0, +1);
|
||||
#endif
|
||||
}
|
||||
|
||||
ISR(INT2_vect) // Arduino2560 IO19 (portD pin2)
|
||||
{
|
||||
uint8_t input = (PIND & 0x0C);
|
||||
#if defined (ROTENC_DIV2)// Rotenc resolution/2
|
||||
if (input == 0) incRotaryEncoder(1, -1);
|
||||
#else
|
||||
if (input == 0 || input == 0x0C) incRotaryEncoder(1, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
ISR(INT3_vect) // Arduino2560 IO18 (portD pin3)
|
||||
{
|
||||
uint8_t input = (PIND & 0x0C);
|
||||
#if defined (ROTENC_DIV2)// Rotenc resolution/2
|
||||
if (input == 0) incRotaryEncoder(1, +1);
|
||||
#else
|
||||
if (input == 0 || input == 0x0C) incRotaryEncoder(1, +1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// RTC driver
|
||||
void rtcSetTime(const struct gtm * tm)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_MEGA2560_H_
|
||||
#define _BOARD_MEGA2560_H_
|
||||
|
||||
#include "../common/avr/board_avr.h"
|
||||
|
||||
// Board driver
|
||||
void boardInit(void);
|
||||
#define boardOff() pwrOff()
|
||||
|
||||
// Keys
|
||||
#define KEYS_GPIO_REG_MENU pinl
|
||||
#define KEYS_GPIO_PIN_MENU (1<<4)
|
||||
#define KEYS_GPIO_REG_EXIT pinl
|
||||
#define KEYS_GPIO_PIN_EXIT (1<<5)
|
||||
#define KEYS_GPIO_REG_RIGHT pinl
|
||||
#define KEYS_GPIO_PIN_RIGHT (1<<2)
|
||||
#define KEYS_GPIO_REG_LEFT pinl
|
||||
#define KEYS_GPIO_PIN_LEFT (1<<3)
|
||||
#define KEYS_GPIO_REG_UP pinl
|
||||
#define KEYS_GPIO_PIN_UP (1<<1)
|
||||
#define KEYS_GPIO_REG_DOWN pinl
|
||||
#define KEYS_GPIO_PIN_DOWN (1<<0)
|
||||
|
||||
#define IS_SHIFT_KEY(index) (false)
|
||||
#define IS_SHIFT_PRESSED() (false)
|
||||
|
||||
// Trims
|
||||
#define NUM_TRIMS 4
|
||||
#define NUM_TRIMS_KEYS (NUM_TRIMS * 2)
|
||||
#define TRIMS_GPIO_REG_LHL pinf
|
||||
#define TRIMS_GPIO_PIN_LHL (1<<7)
|
||||
#define TRIMS_GPIO_REG_LVD pinf
|
||||
#define TRIMS_GPIO_PIN_LVD (1<<5)
|
||||
#define TRIMS_GPIO_REG_RVU pinf
|
||||
#define TRIMS_GPIO_PIN_RVU (1<<2)
|
||||
#define TRIMS_GPIO_REG_RHL pinf
|
||||
#define TRIMS_GPIO_PIN_RHL (1<<1)
|
||||
#define TRIMS_GPIO_REG_LHR pinf
|
||||
#define TRIMS_GPIO_PIN_LHR (1<<6)
|
||||
#define TRIMS_GPIO_REG_LVU pinf
|
||||
#define TRIMS_GPIO_PIN_LVU (1<<4)
|
||||
#define TRIMS_GPIO_REG_RVD pinf
|
||||
#define TRIMS_GPIO_PIN_RVD (1<<3)
|
||||
#define TRIMS_GPIO_REG_RHR pinf
|
||||
#define TRIMS_GPIO_PIN_RHR (1<<0)
|
||||
|
||||
#define TIMER_16KHZ_VECT TIMER2_OVF_vect
|
||||
#define COUNTER_16KHZ TCNT2
|
||||
#define TIMER_10MS_VECT TIMER2_COMPA_vect
|
||||
#define TIMER_10MS_COMPVAL OCR2A
|
||||
#define PAUSE_10MS_INTERRUPT() TIMSK2 &= ~(1<<OCIE2A)
|
||||
#define RESUME_10MS_INTERRUPT() TIMSK2 |= (1<<OCIE2A)
|
||||
#define PAUSE_PPMIN_INTERRUPT() TIMSK3 &= ~(1<<ICIE3)
|
||||
#define RESUME_PPMIN_INTERRUPT() TIMSK3 |= (1<<ICIE3)
|
||||
|
||||
#define SLAVE_MODE() ~PINH & (1<<INP_H_RF_Activated)
|
||||
#define JACK_PPM_OUT() PORTB &= ~(1<<OUT_B_SIM_CTL)
|
||||
#define JACK_PPM_IN() PORTB |= (1<<OUT_B_SIM_CTL)
|
||||
|
||||
// Backlight driver
|
||||
#define backlightEnable() PORTC |= (1<<OUT_C_LIGHT)
|
||||
#define backlightDisable() PORTC &= ~(1<<OUT_C_LIGHT)
|
||||
#define isBacklightEnabled() (PORTC & (1<<OUT_C_LIGHT))
|
||||
#define BACKLIGHT_ENABLE() backlightEnable()
|
||||
#define BACKLIGHT_DISABLE() backlightDisable()
|
||||
|
||||
// SD driver
|
||||
#define BLOCK_SIZE 512 /* Block Size in Bytes */
|
||||
#define sdDone()
|
||||
#define SD_IS_HC() (0)
|
||||
#define SD_GET_SPEED() (0)
|
||||
#if !defined(SIMU)
|
||||
bool sdMounted(void);
|
||||
void sdMountPoll(void);
|
||||
void sdPoll10ms(void);
|
||||
#endif
|
||||
|
||||
// Switchs driver
|
||||
#define INP_C_ID2 1
|
||||
#define INP_C_ID1 0
|
||||
#define INP_D_AileDR 7
|
||||
#define INP_G_ThrCt 2
|
||||
#define INP_G_Gear 1
|
||||
#define INP_G_RuddDR 0
|
||||
#define INP_L_ElevDR 6
|
||||
#define INP_L_Trainer 7
|
||||
|
||||
// Servitudes driver
|
||||
#define INP_E_PPM_IN 7 //directly used
|
||||
#define INP_B_VoiceBuzy 7 //directly used
|
||||
#define OUT_B_PPM 6
|
||||
#define OUT_B_SIM_CTL 5
|
||||
#define I_O_B_UNUSED 4 //unused, was Buzzer
|
||||
#define INP_D_I2C_SCL 1
|
||||
#define INP_D_I2C_SDA 0
|
||||
#define OUT_E_VoiceData 3
|
||||
#define INP_E_TELEM_RX 1
|
||||
#define OUT_E_TELEM_TX 0
|
||||
#define OUT_G_VoiceClock 5
|
||||
#define INP_H_RF_Activated 6
|
||||
#define INP_H_DSC_Activated 5 //pwrCheck(), directly used
|
||||
#define INP_H_Hold_Power 4 //pwrCheck(), directly used
|
||||
#define OUT_H_SpeakerBuzzer 3
|
||||
#define OUT_H_VoiceReset 1
|
||||
#define OUT_H_HAPTIC 0
|
||||
|
||||
// Rotary encoders driver
|
||||
#define INP_E_ROT_ENC_1_A 4
|
||||
#define INP_E_ROT_ENC_1_B 5
|
||||
#define INP_D_ROT_ENC_2_A 2
|
||||
#define INP_D_ROT_ENC_2_B 3
|
||||
#define INP_J_ROT_ENC_1_PUSH 0
|
||||
#define INP_J_ROT_ENC_2_PUSH 1
|
||||
#define REA_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_1_PUSH))
|
||||
#define REB_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_2_PUSH))
|
||||
#define ROTENC_DOWN() (REA_DOWN() || REB_DOWN())
|
||||
#define ROTENC_DIV2 // rotary encoders resolution/2
|
||||
|
||||
// LCD driver
|
||||
#define PORTA_LCD_DAT PORTA
|
||||
#define PORTC_LCD_CTRL PORTC
|
||||
#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 (CS2)
|
||||
#else // and connect KS108 R/W pin to ground via a 1k resistor
|
||||
#define OUT_C_LCD_RnW 6
|
||||
#endif
|
||||
#define OUT_C_LCD_E 7
|
||||
#define OUT_C_LCD_A0 5
|
||||
#define OUT_C_LCD_RES 4
|
||||
#define OUT_C_LCD_CS1 3
|
||||
#define OUT_C_LIGHT 2
|
||||
|
||||
// DBLKeys driver
|
||||
#define KEYS_PRESSED() (~PINL)
|
||||
|
||||
// Power driver
|
||||
uint8_t pwrCheck();
|
||||
void pwrOff();
|
||||
#if defined(PWRMANAGE)
|
||||
#define UNEXPECTED_SHUTDOWN() ((mcusr & (1 << WDRF)) || g_eeGeneral.unexpectedShutdown)
|
||||
#else
|
||||
#define UNEXPECTED_SHUTDOWN() (mcusr & (1 << WDRF))
|
||||
#endif
|
||||
|
||||
// USB fake driver
|
||||
#define usbPlugged() false
|
||||
|
||||
// Haptic driver
|
||||
#define hapticOn() PORTH |= (1 << OUT_H_HAPTIC)
|
||||
#define hapticOff() PORTH &= ~(1 << OUT_H_HAPTIC)
|
||||
|
||||
// Buzzer driver
|
||||
#define buzzerOn() PORTH |= (1 << OUT_H_SpeakerBuzzer)
|
||||
#define buzzerOff() PORTH &= ~(1 << OUT_H_SpeakerBuzzer)
|
||||
|
||||
// Speaker driver
|
||||
#if defined(AUDIO)
|
||||
#define speakerOn() TCCR4A |= (1 << COM4A0)
|
||||
#define speakerOff() TCCR4A &= ~(1 << COM4A0)
|
||||
#endif
|
||||
|
||||
// Voice driver (WTV20)
|
||||
#if defined(VOICE_WTV20)
|
||||
#define WTV20_Data_on PORTE |= (1<<OUT_E_VoiceData)
|
||||
#define WTV20_Data_off PORTE &= ~(1<<OUT_E_VoiceData)
|
||||
#define WTV20_BUSY (PINB & (1<<INP_B_VoiceBuzy))
|
||||
#define WTV20_Clock_on PORTG |= (1<<OUT_G_VoiceClock)
|
||||
#define WTV20_Clock_off PORTG &= ~(1<<OUT_G_VoiceClock)
|
||||
#define WTV20_CLK (PING & (1<<OUT_G_VoiceClock))
|
||||
#define WTV20_Reset_on PORTH |= (1<<OUT_H_VoiceReset)
|
||||
#define WTV20_Reset_off PORTH &= ~(1<<OUT_H_VoiceReset)
|
||||
#endif
|
||||
|
||||
// Voice driver (JQ6500)
|
||||
#if defined(VOICE_JQ6500)
|
||||
#define JQ6500_Serial_on PORTE |= (1<<OUT_E_VoiceData)
|
||||
#define JQ6500_Serial_off PORTE &= ~(1<<OUT_E_VoiceData)
|
||||
#define JQ6500_BUSY (PINB & (1<<INP_B_VoiceBuzy))
|
||||
#endif
|
||||
|
||||
// Battery driver
|
||||
#define BATTERY_MIN 90 // 9V
|
||||
#define BATTERY_MAX 120 // 12V
|
||||
#define BATTERY_WARN 90 // 9V
|
||||
|
||||
// Analogs driver
|
||||
#define NUM_MOUSE_ANALOGS 0
|
||||
#define NUM_DUMMY_ANAS 0
|
||||
|
||||
#endif // _BOARD_MEGA2560_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// From https://github.com/g4lvanix/I2C-master-lib
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <util/twi.h>
|
||||
|
||||
#include "i2c_driver.h"
|
||||
|
||||
//#define F_SCL 400000UL // SCL frequency
|
||||
#define F_SCL 800000UL // SCL frequency
|
||||
#define Prescaler 1
|
||||
#define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16 ) / 2)
|
||||
|
||||
void wait()
|
||||
{
|
||||
while( !(TWCR & (1<<TWINT)) );
|
||||
}
|
||||
|
||||
void i2c_init(void)
|
||||
{
|
||||
TWBR = (uint8_t)TWBR_val;
|
||||
}
|
||||
|
||||
uint8_t i2c_start(uint8_t address)
|
||||
{
|
||||
// reset TWI control register
|
||||
TWCR = 0;
|
||||
// transmit START condition
|
||||
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
|
||||
// wait for end of transmission
|
||||
wait();
|
||||
|
||||
// check if the start condition was successfully transmitted
|
||||
if((TWSR & 0xF8) != TW_START){ return 1; }
|
||||
|
||||
// load slave address into data register
|
||||
TWDR = address;
|
||||
// start transmission of address
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
// wait for end of transmission
|
||||
wait();
|
||||
// check if the device has acknowledged the READ / WRITE mode
|
||||
uint8_t twst = TW_STATUS & 0xF8;
|
||||
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t i2c_write(uint8_t data)
|
||||
{
|
||||
// load data into data register
|
||||
TWDR = data;
|
||||
// start transmission of data
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
// wait for end of transmission
|
||||
wait();
|
||||
|
||||
if( (TWSR & 0xF8) != TW_MT_DATA_ACK ){ return 1; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t i2c_read_ack(void)
|
||||
{
|
||||
|
||||
// start TWI module and acknowledge data after reception
|
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
|
||||
// wait for end of transmission
|
||||
wait();
|
||||
// return received data from TWDR
|
||||
return TWDR;
|
||||
}
|
||||
|
||||
uint8_t i2c_read_nack(void)
|
||||
{
|
||||
|
||||
// start receiving without acknowledging reception
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
// wait for end of transmission
|
||||
wait();
|
||||
// return received data from TWDR
|
||||
return TWDR;
|
||||
}
|
||||
|
||||
uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length)
|
||||
{
|
||||
if (i2c_start(address | I2C_WRITE)) return 1;
|
||||
|
||||
for (uint16_t i = 0; i < length; i++)
|
||||
{
|
||||
if (i2c_write(data[i])) return 1;
|
||||
}
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length)
|
||||
{
|
||||
if (i2c_start(address | I2C_READ)) return 1;
|
||||
|
||||
for (uint16_t i = 0; i < (length-1); i++)
|
||||
{
|
||||
data[i] = i2c_read_ack();
|
||||
}
|
||||
data[(length-1)] = i2c_read_nack();
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length)
|
||||
{
|
||||
if (i2c_start(devaddr | 0x00)) return 1;
|
||||
|
||||
i2c_write(regaddr);
|
||||
|
||||
for (uint16_t i = 0; i < length; i++)
|
||||
{
|
||||
if (i2c_write(data[i])) return 1;
|
||||
}
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length)
|
||||
{
|
||||
if (i2c_start(devaddr)) return 1;
|
||||
|
||||
i2c_write(regaddr);
|
||||
|
||||
if (i2c_start(devaddr | 0x01)) return 1;
|
||||
|
||||
for (uint16_t i = 0; i < (length-1); i++)
|
||||
{
|
||||
data[i] = i2c_read_ack();
|
||||
}
|
||||
data[(length-1)] = i2c_read_nack();
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i2c_stop(void)
|
||||
{
|
||||
// transmit STOP condition
|
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||||
}
|
||||
|
||||
uint8_t iic_read (
|
||||
uint8_t dev, /* Device address */
|
||||
uint8_t adr, /* Read start address */
|
||||
uint16_t cnt, /* Read uint8_t count */
|
||||
uint8_t *buff /* Read data buffer */
|
||||
)
|
||||
{
|
||||
uint8_t ret;
|
||||
ret = i2c_readReg(dev, adr, buff, cnt);
|
||||
return (!ret);
|
||||
}
|
||||
|
||||
uint8_t iic_write (
|
||||
uint8_t dev, /* Device address */
|
||||
uint8_t adr, /* Write start address */
|
||||
uint16_t cnt, /* Write uint8_t count */
|
||||
const uint8_t *buff /* Data to be written */
|
||||
)
|
||||
{
|
||||
uint8_t ret;
|
||||
ret = i2c_writeReg(dev, adr, (uint8_t *)buff, cnt);
|
||||
return (!ret);
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// From https://github.com/g4lvanix/I2C-master-lib
|
||||
|
||||
#ifndef I2C_DRIVER_H
|
||||
#define I2C_DRIVER_H
|
||||
|
||||
#define I2C_READ 0x01
|
||||
#define I2C_WRITE 0x00
|
||||
|
||||
void i2c_init(void);
|
||||
uint8_t i2c_start(uint8_t address);
|
||||
uint8_t i2c_write(uint8_t data);
|
||||
uint8_t i2c_read_ack(void);
|
||||
uint8_t i2c_read_nack(void);
|
||||
uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length);
|
||||
uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length);
|
||||
uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length);
|
||||
uint8_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length);
|
||||
void i2c_stop(void);
|
||||
|
||||
// M2560 functions
|
||||
|
||||
uint8_t iic_read (
|
||||
uint8_t dev, /* Device address */
|
||||
uint8_t adr, /* Read start address */
|
||||
uint16_t cnt, /* Read uint8_t count */
|
||||
uint8_t *buff /* Read data buffer */
|
||||
);
|
||||
|
||||
uint8_t iic_write (
|
||||
uint8_t dev, /* Device address */
|
||||
uint8_t adr, /* Write start address */
|
||||
uint16_t cnt, /* Write uint8_t count */
|
||||
const uint8_t *buff /* Data to be written */
|
||||
);
|
||||
|
||||
#endif // I2C_DRIVER_H
|
||||
/*
|
||||
##### void I2C_init(void)
|
||||
This function needs to be called only once to set up the correct SCL frequency
|
||||
for the bus
|
||||
|
||||
##### uint8_t I2C_start(uint8_t address)
|
||||
This function needs to be called any time a connection to a new slave device should
|
||||
be established. The function returns 1 if an error has occurred, otherwise it returns
|
||||
0.
|
||||
|
||||
The syntax to start a operation write to a device is either:
|
||||
`I2C_start(SLAVE_ADDRESS+I2C_WRITE);`
|
||||
or
|
||||
`I2C_start(SLAVE_WRITE_ADDRESS);`
|
||||
|
||||
The syntax to start a read operation from a device is either:
|
||||
`I2C_start(SLAVE_ADDRESS+I2C_READ);`
|
||||
or
|
||||
`I2C_start(SLAVE_READ_ADDRESS);`
|
||||
|
||||
##### uint8_t I2C_write(uint8_t data)
|
||||
This function is used to write data to the currently active device.
|
||||
The only parameter this function takes is the 8 bit unsigned integer to be sent.
|
||||
The function returns 1 if an error has occurred, otherwise it returns
|
||||
0.
|
||||
|
||||
##### uint8_t I2C_read_ack(void)
|
||||
This function is used to read one byte from a device and request another byte of data
|
||||
after the transmission is complete by sending the acknowledge bit.
|
||||
This function returns the received byte.
|
||||
|
||||
##### uint8_t I2C_read_nack(void)
|
||||
This function is used to read one byte from a device an then not requesting another
|
||||
byte and therefore stopping the current transmission.
|
||||
This function returns the received byte.
|
||||
|
||||
##### uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length);
|
||||
This function is used to transmit [length] number of bytes to an I2C device with the given
|
||||
I2C address from [data].
|
||||
The [address] passed to this function is the 7-bit slave address, left
|
||||
shifted by one bit (i.e. 7-bit slave address is `0x2F` -> `(0x2F)<<1` = `0x5E`)
|
||||
|
||||
##### uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length);
|
||||
This function is used to read [length] number of bytes from the I2C device with the given
|
||||
I2C address into the [data].
|
||||
The [address] passed to this function is the 7-bit slave address, left
|
||||
shifted by one bit (i.e. 7-bit slave address is `0x2F` -> `(0x2F)<<1` = `0x5E`)
|
||||
|
||||
##### void I2C_stop(void)
|
||||
This function disables the TWI peripheral completely
|
||||
and therefore disconnects the device from the bus.
|
||||
*/
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#if defined(VOICE_WTV20)
|
||||
#include "targets/mega2560/voice_wtv20.cpp"
|
||||
#elif defined(VOICE_JQ6500)
|
||||
#include "targets/mega2560/voice_jq6500.cpp"
|
||||
#endif
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* 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 bool 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)
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// JQ6500 mp3 module driver
|
||||
// 6 X 10 (bits) X 104µs = 6.24 mS to send a playfile command
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#define QUEUE_LENGTH 16*2 //bytes
|
||||
|
||||
enum JQ6500_State
|
||||
{
|
||||
START = 0x7E, //Start
|
||||
NUMBY = 0x04, //Num bytes follow
|
||||
SELEC = 0X03, //Select file
|
||||
FILEH = 0x00, //Dummy file
|
||||
FILEL = 0x01, //Dummy file
|
||||
TERMI = 0xEF //Termination
|
||||
};
|
||||
|
||||
JQ6500_State state = START;
|
||||
uint8_t JQ6500_playlist[QUEUE_LENGTH] = {0};
|
||||
volatile uint8_t JQ6500_InputIndex = 0;
|
||||
uint8_t JQ6500_PlayIndex = 0;
|
||||
|
||||
bool isPlaying()
|
||||
{
|
||||
/* interrupts active on Output Compare A Match ? */
|
||||
#if defined(SIMU)
|
||||
return false;
|
||||
#else
|
||||
return (TIMSK5 & (1<<OCIE5A));
|
||||
#endif
|
||||
}
|
||||
|
||||
void pushPrompt(uint16_t prompt)
|
||||
{
|
||||
// if mute active => no voice
|
||||
if (g_eeGeneral.beepMode == e_mode_quiet) return;
|
||||
++prompt; // With SDformatter, first FAT address = 1 ? Not all th time ??
|
||||
/* Load playlist and activate interrupt */
|
||||
JQ6500_playlist[JQ6500_InputIndex] = (uint8_t)(prompt >> 8); // MSB first
|
||||
++JQ6500_InputIndex;
|
||||
JQ6500_playlist[JQ6500_InputIndex] = (uint8_t)(prompt & 0xFF); // LSB after
|
||||
++JQ6500_InputIndex;
|
||||
if (JQ6500_InputIndex == QUEUE_LENGTH) JQ6500_InputIndex = 0;
|
||||
if (!isPlaying()) {
|
||||
TCNT5=0;
|
||||
OCR5A = 0xFA;
|
||||
TIMSK5 |= (1<<OCIE5A); // enable interrupts on Output Compare A Match
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t JQ6500_sendbyte(uint8_t Data_byte)
|
||||
{
|
||||
static uint8_t i = 0;
|
||||
|
||||
if (!i) { JQ6500_Serial_off; ++i; return 0; } // serial start bit
|
||||
|
||||
if (i==9) { JQ6500_Serial_on; i = 0; return 1; } // serial stop bit
|
||||
|
||||
if ((Data_byte >> (i-1)) & 0x01) { JQ6500_Serial_on;} else { JQ6500_Serial_off;} // send data bits
|
||||
++i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(SIMU)
|
||||
ISR(TIMER5_COMPA_vect) // every 104µS
|
||||
{
|
||||
sei();
|
||||
|
||||
if (state == START) { OCR5A = 0x19; if (JQ6500_BUSY) return; if (JQ6500_sendbyte(state)) { state = NUMBY; return; } }
|
||||
|
||||
if (state == NUMBY) { if (JQ6500_sendbyte(state)) { state = SELEC; return; } }
|
||||
|
||||
if (state == SELEC) { if (JQ6500_sendbyte(state)) { state = FILEH; return; } }
|
||||
|
||||
if (state == FILEH) { if (JQ6500_sendbyte(JQ6500_playlist[JQ6500_PlayIndex])) { ++JQ6500_PlayIndex; state = FILEL; return; } }
|
||||
|
||||
if (state == FILEL) { if (JQ6500_sendbyte(JQ6500_playlist[JQ6500_PlayIndex])) { ++JQ6500_PlayIndex; state = TERMI; return; } }
|
||||
|
||||
if (state == TERMI) {
|
||||
if (JQ6500_sendbyte(state)) {
|
||||
state = START;
|
||||
if (JQ6500_PlayIndex == QUEUE_LENGTH) JQ6500_PlayIndex = 0;
|
||||
if (JQ6500_PlayIndex == JQ6500_InputIndex) { OCR5A = 0x19; TIMSK5 &= ~(1<<OCIE5A); } // stop reentrance
|
||||
return; }
|
||||
}
|
||||
|
||||
cli();
|
||||
}
|
||||
#endif
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// WTV20SDMini module driver, adapted from somo14d driver (gruvin9x board)
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
// Start and stop bits need to be 2ms in duration. Start bit is low, stop bit is high
|
||||
#define WTV20_STOP_TIME 84 // This is the needed 2ms (4) + 40ms (80) to allow for the
|
||||
// point at which the busy flag is checkable + 2ms for saftey (4)
|
||||
#define WTV20_START_TIME 5 // The 2ms of a stop/start bit
|
||||
|
||||
enum WTV20_State
|
||||
{
|
||||
RESET,
|
||||
RESETPAUSE,
|
||||
PAUSE,
|
||||
SENDSTART,
|
||||
SENDDATA,
|
||||
SENDSTOP
|
||||
};
|
||||
|
||||
#define QUEUE_LENGTH 10
|
||||
uint16_t WTV20_playlist[QUEUE_LENGTH] = {0};
|
||||
volatile uint8_t WTV20_InputIndex = 0;
|
||||
uint8_t WTV20_PlayIndex = 4; // Also used for reset,(save 2 static uint8_t)
|
||||
uint8_t Startstop = WTV20_START_TIME;
|
||||
uint16_t WTV20_current = 0;
|
||||
uint8_t state = RESET;
|
||||
|
||||
void WTV20_sendstart()
|
||||
{
|
||||
WTV20_Clock_off; // Start Bit, CLK low for 2ms
|
||||
|
||||
--Startstop;
|
||||
|
||||
if (!Startstop) state = SENDDATA;
|
||||
}
|
||||
|
||||
void WTV20_senddata()
|
||||
{
|
||||
static uint8_t i = 0;
|
||||
|
||||
if (!WTV20_CLK) {
|
||||
// Only change data when the CLK is low
|
||||
if (WTV20_current & 0x8000) {
|
||||
WTV20_Data_on; // Data high
|
||||
}
|
||||
WTV20_current = (WTV20_current << 1);
|
||||
++i;
|
||||
_delay_us(1); // Data setup delay
|
||||
WTV20_Clock_on; // CLK high
|
||||
}
|
||||
else {
|
||||
// Don't alter after sending last bit in preparation for sending stop bit
|
||||
WTV20_Clock_off; // CLK low
|
||||
WTV20_Data_off; // Data low
|
||||
}
|
||||
|
||||
if (i == 16) { i = 0; Startstop = WTV20_STOP_TIME; state = SENDSTOP; }
|
||||
}
|
||||
|
||||
void WTV20_sendstop()
|
||||
{
|
||||
WTV20_Data_off; // Data low
|
||||
WTV20_Clock_on; // Stop Bit, CLK high for 2ms
|
||||
--Startstop;
|
||||
|
||||
if (!Startstop && !WTV20_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 */
|
||||
WTV20_playlist[WTV20_InputIndex] = prompt;
|
||||
++WTV20_InputIndex;
|
||||
if (WTV20_InputIndex == QUEUE_LENGTH) WTV20_InputIndex = 0;
|
||||
|
||||
if (!isPlaying()) {
|
||||
TIMSK5 |= (1<<OCIE5A); // enable interrupts on Output Compare A Match
|
||||
}
|
||||
}
|
||||
|
||||
bool 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
|
||||
{
|
||||
sei();
|
||||
if (state == PAUSE) {
|
||||
if (WTV20_PlayIndex == WTV20_InputIndex) {
|
||||
TIMSK5 &= ~(1<<OCIE5A); // stop reentrance
|
||||
TCNT5=0; // reset timer
|
||||
return; // nothing else to play
|
||||
}
|
||||
else {
|
||||
WTV20_current = WTV20_playlist[WTV20_PlayIndex];
|
||||
++WTV20_PlayIndex;
|
||||
if (WTV20_PlayIndex == QUEUE_LENGTH) WTV20_PlayIndex = 0;
|
||||
Startstop = WTV20_START_TIME;
|
||||
state = SENDSTART;
|
||||
}
|
||||
} // end PAUSE
|
||||
|
||||
if (state == SENDSTART) {
|
||||
WTV20_sendstart();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == SENDDATA) {
|
||||
WTV20_senddata();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == SENDSTOP) {
|
||||
WTV20_sendstop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == RESET) {
|
||||
if (WTV20_PlayIndex) { // WTV20_PlayIndex used as reset counter
|
||||
// OCR5A=0x1f4; setted in board_mega2560.cpp
|
||||
WTV20_Reset_off;
|
||||
WTV20_Data_off;
|
||||
WTV20_Clock_on;
|
||||
--WTV20_PlayIndex;
|
||||
return;
|
||||
} // RESET low
|
||||
else {
|
||||
state = RESETPAUSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == RESETPAUSE) {
|
||||
WTV20_Reset_on; // RESET high
|
||||
if (!WTV20_BUSY) {
|
||||
state = PAUSE;
|
||||
OCR5A = 0x7d; // 0.5 ms after init
|
||||
}
|
||||
}
|
||||
cli();
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user