5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
24 #include "i2c_driver.h"
28 uint32_t Master_frequency
;
29 volatile uint8_t lcdLock
;
30 volatile uint32_t lcdInputs
;
32 uint16_t Current_analogue
;
34 uint32_t Current_accumulator
;
35 uint32_t Current_used
;
37 extern "C" void sam_boot( void ) ;
40 // Free pins (PA16 is stock buzzer)
41 // PA23, PA24, PA25, PB7, PB13
42 // PC20, PC21(labelled 17), PC22, PC24
44 // PA25, use for stock buzzer
46 // PC21, PC19, PC15 (PPM2 output)
47 inline void config_free_pins()
49 configure_pins( PIO_PB14
, PIN_ENABLE
| PIN_INPUT
| PIN_PORTB
| PIN_PULLUP
) ;
52 // Assumes PMC has already enabled clocks to ports
53 inline void setup_switches()
55 configure_pins( 0x01808087, PIN_ENABLE
| PIN_INPUT
| PIN_PORTA
| PIN_PULLUP
) ;
56 configure_pins( 0x00000030, PIN_ENABLE
| PIN_INPUT
| PIN_PORTB
| PIN_PULLUP
) ;
57 configure_pins( 0x91114900, PIN_ENABLE
| PIN_INPUT
| PIN_PORTC
| PIN_PULLUP
) ;
60 inline void UART3_Configure(uint32_t baudrate
, uint32_t masterClock
)
62 Uart
*pUart
= BT_USART
;
65 configure_pins( (PIO_PB2
| PIO_PB3
), PIN_PERIPHERAL
| PIN_INPUT
| PIN_PER_A
| PIN_PORTB
| PIN_NO_PULLUP
) ;
68 PMC
->PMC_PCER0
= 1 << BT_ID
;
70 /* Reset and disable receiver & transmitter */
71 pUart
->UART_CR
= UART_CR_RSTRX
| UART_CR_RSTTX
72 | UART_CR_RXDIS
| UART_CR_TXDIS
;
75 pUart
->UART_MR
= 0x800 ; // NORMAL, No Parity
77 /* Configure baudrate */
78 /* Asynchronous, no oversampling */
79 pUart
->UART_BRGR
= ( (masterClock
/ baudrate
) + 8 ) / 16;
81 /* Disable PDC channel */
82 pUart
->UART_PTCR
= UART_PTCR_RXTDIS
| UART_PTCR_TXTDIS
;
84 /* Enable receiver and transmitter */
85 pUart
->UART_CR
= UART_CR_RXEN
| UART_CR_TXEN
;
88 pUart
->UART_IER
= UART_IER_RXRDY
;
89 NVIC_EnableIRQ(UART1_IRQn
) ;
95 BT_USART
->UART_IDR
= UART_IDR_RXRDY
;
96 NVIC_DisableIRQ(UART1_IRQn
) ;
99 // Starts TIMER0 at full speed (MCK/2) for delay timing
100 // @ 36MHz this is 18MHz
101 // This was 6 MHz, we may need to slow it to TIMER_CLOCK2 (MCK/8=4.5 MHz)
102 inline void start_timer0()
106 // Enable peripheral clock TC0 = bit 23 thru TC5 = bit 28
107 PMC
->PMC_PCER0
|= 0x00800000L
; // Enable peripheral clock to TC0
109 ptc
= TC0
; // Tc block 0 (TC0-2)
110 ptc
->TC_BCR
= 0 ; // No sync
112 ptc
->TC_CHANNEL
[0].TC_CMR
= 0x00008001 ; // Waveform mode MCK/8 for 36MHz osc.
113 ptc
->TC_CHANNEL
[0].TC_RC
= 0xFFF0 ;
114 ptc
->TC_CHANNEL
[0].TC_RA
= 0 ;
115 ptc
->TC_CHANNEL
[0].TC_CMR
= 0x00008040 ; // 0000 0000 0000 0000 1000 0000 0100 0000, stop at regC
116 ptc
->TC_CHANNEL
[0].TC_CCR
= 5 ; // Enable clock and trigger it (may only need trigger)
119 // TIMER2 at 200Hz, provides 5mS for sound and 10mS tick on interrupt
120 // Starts TIMER2 at 200Hz, commentd out drive of TIOA2 (A26, EXT2)
121 inline void start_timer2()
126 // Enable peripheral clock TC0 = bit 23 thru TC5 = bit 28
127 PMC
->PMC_PCER0
|= 0x02000000L
; // Enable peripheral clock to TC2
129 timer
= Master_frequency
/ 12800 / 2; // MCK/128 and 200 Hz
131 ptc
= TC0
; // Tc block 0 (TC0-2)
132 ptc
->TC_BCR
= 0 ; // No sync
134 ptc
->TC_CHANNEL
[2].TC_CMR
= 0x00008000 ; // Waveform mode
135 ptc
->TC_CHANNEL
[2].TC_RC
= timer
; // 10 Hz
136 ptc
->TC_CHANNEL
[2].TC_RA
= timer
>> 1 ;
137 ptc
->TC_CHANNEL
[2].TC_CMR
= 0x0009C003 ; // 0000 0000 0000 1001 1100 0000 0000 0011
138 ptc
->TC_CHANNEL
[2].TC_CCR
= 5 ; // Enable clock and trigger it (may only need trigger)
140 NVIC_EnableIRQ(TC2_IRQn
) ;
141 TC0
->TC_CHANNEL
[2].TC_IER
= TC_IER0_CPCS
;
146 static uint32_t pre_scale
; // Used to get 10 Hz counter
150 if ( ++pre_scale
>= 2 ) {
157 extern "C" void TC2_IRQHandler()
161 /* Clear status bit to acknowledge interrupt */
162 dummy
= TC0
->TC_CHANNEL
[2].TC_SR
;
163 (void) dummy
; // Discard value - prevents compiler warning
168 // PWM used for PPM generation, and LED Backlight
169 // Output pin PB5 not used, PA17 used as PWMH3 peripheral C
170 // PWM peripheral ID = 31 (0x80000000)
171 // Ensure PB5 is three state/input, used on REVB for MENU KEY
173 // Configure PWM3 as PPM drive,
174 // PWM0 is LED backlight PWM on PWMH0
175 // This is PC18 peripheral B, Also enable PC22 peripheral B, this is PPM-JACK (PWML3)
178 // PWML2, output as peripheral C on PA16, is for HAPTIC
179 // For testing, just drive it out with PWM
180 // PWML1 for PPM2 output as peripheral B on PC15
181 // For testing, just drive it out with PWM
187 PMC
->PMC_PCER0
|= ( 1 << ID_PWM
) ; // Enable peripheral clock to PWM
189 MATRIX
->CCFG_SYSIO
|= 0x00000020L
; // Disable TDO let PB5 work!
192 configure_pins( PIO_PA16
, PIN_PERIPHERAL
| PIN_INPUT
| PIN_PER_C
| PIN_PORTA
| PIN_NO_PULLUP
) ;
194 configure_pins( PIO_PC18
, PIN_PERIPHERAL
| PIN_INPUT
| PIN_PER_B
| PIN_PORTC
| PIN_NO_PULLUP
) ;
195 configure_pins( PIO_PC22
, PIN_PERIPHERAL
| PIN_INPUT
| PIN_PER_B
| PIN_PORTC
| PIN_NO_PULLUP
) ;
197 // Configure clock - depends on MCK frequency
198 timer
= Master_frequency
/ 2000000 ;
199 timer
|= ( Master_frequency
/ ( 32* 10000 ) ) << 16 ;
200 timer
&= 0x00FF00FF ;
203 pwmptr
->PWM_CLK
= 0x05000000 | timer
; // MCK for DIVA, DIVA = 18 gives 0.5uS clock period @35MHz // MCK/32 / timer = 10000Hz for CLKB
205 // PWM0 for LED backlight
206 pwmptr
->PWM_CH_NUM
[0].PWM_CMR
= 0x0000000C ; // CLKB
207 pwmptr
->PWM_CH_NUM
[0].PWM_CPDR
= 100 ; // Period
208 pwmptr
->PWM_CH_NUM
[0].PWM_CPDRUPD
= 100 ; // Period
209 pwmptr
->PWM_CH_NUM
[0].PWM_CDTY
= 40 ; // Duty
210 pwmptr
->PWM_CH_NUM
[0].PWM_CDTYUPD
= 40 ; // Duty
211 pwmptr
->PWM_ENA
= PWM_ENA_CHID0
; // Enable channel 0
213 // PWM2 for HAPTIC drive 100Hz test
214 pwmptr
->PWM_CH_NUM
[2].PWM_CMR
= 0x0000000C ; // CLKB
215 pwmptr
->PWM_CH_NUM
[2].PWM_CPDR
= 100 ; // Period
216 pwmptr
->PWM_CH_NUM
[2].PWM_CPDRUPD
= 100 ; // Period
217 pwmptr
->PWM_CH_NUM
[2].PWM_CDTY
= 40 ; // Duty
218 pwmptr
->PWM_CH_NUM
[2].PWM_CDTYUPD
= 40 ; // Duty
219 pwmptr
->PWM_OOV
&= ~0x00040000 ; // Force low
220 pwmptr
->PWM_OSS
= 0x00040000 ; // Force low
221 // pwmptr->PWM_ENA = PWM_ENA_CHID2 ; // Enable channel 2
239 #define LCD_DATA 0x000000FFL
240 #define LCD_A0 0x00000080L
241 #define LCD_RnW 0x00002000L
242 #define LCD_E 0x00001000L
243 #define LCD_CS1 0x04000000L
244 #define LCD_RES 0x08000000L
246 void configure_pins( uint32_t pins
, uint16_t config
)
250 pioptr
= PIOA
+ ((config
& PIN_PORT_MASK
) >> 6);
251 if (config
& PIN_PULLUP
) {
252 pioptr
->PIO_PPDDR
= pins
;
253 pioptr
->PIO_PUER
= pins
;
256 pioptr
->PIO_PUDR
= pins
;
259 if (config
& PIN_PULLDOWN
) {
260 pioptr
->PIO_PUDR
= pins
;
261 pioptr
->PIO_PPDER
= pins
;
264 pioptr
->PIO_PPDDR
= pins
;
267 if (config
& PIN_HIGH
) {
268 pioptr
->PIO_SODR
= pins
;
271 pioptr
->PIO_CODR
= pins
;
274 if (config
& PIN_INPUT
) {
275 pioptr
->PIO_ODR
= pins
;
278 pioptr
->PIO_OER
= pins
;
281 if (config
& PIN_PERI_MASK_L
) {
282 pioptr
->PIO_ABCDSR
[0] |= pins
;
285 pioptr
->PIO_ABCDSR
[0] &= ~pins
;
288 if (config
& PIN_PERI_MASK_H
) {
289 pioptr
->PIO_ABCDSR
[1] |= pins
;
292 pioptr
->PIO_ABCDSR
[1] &= ~pins
;
295 if (config
& PIN_ENABLE
) {
296 pioptr
->PIO_PER
= pins
;
299 pioptr
->PIO_PDR
= pins
;
303 void opentxBootloader();
305 // Set up for volume control (TWI0)
306 // Need PA3 and PA4 set to peripheral A
307 #if !defined(PCBAR9X)
313 PMC
->PMC_PCER0
|= 0x00080000L
; // Enable peripheral clock to TWI0
315 TWI0
->TWI_CR
= TWI_CR_SWRST
; // Reset in case we are restarting
319 pioptr
->PIO_ABCDSR
[0] &= ~0x00000018 ; // Peripheral A
320 pioptr
->PIO_ABCDSR
[1] &= ~0x00000018 ; // Peripheral A
321 pioptr
->PIO_PDR
= 0x00000018 ; // Assign to peripheral
323 timing
= Master_frequency
* 5 / 1000000 ; // 5uS high and low
326 timing
|= timing
<< 8 ;
328 TWI0
->TWI_CWGR
= 0x00040000 | timing
; // TWI clock set
329 TWI0
->TWI_CR
= TWI_CR_MSEN
| TWI_CR_SVDIS
; // Master mode enable
330 TWI0
->TWI_MMR
= 0x002F0000 ; // Device 5E (>>1) and master is writing
331 NVIC_EnableIRQ(TWI0_IRQn
) ;
339 ResetReason
= RSTC
->RSTC_SR
;
341 MATRIX
->CCFG_SYSIO
|= 0x000000F0L
; // Disable syspins, enable B4,5,6,7
343 PMC
->PMC_PCER0
= (1<<ID_PIOC
)|(1<<ID_PIOB
)|(1<<ID_PIOA
)|(1<<ID_UART0
) ; // Enable clocks to PIOB and PIOA and PIOC and UART0
345 PIOC
->PIO_PER
= PIO_PC25
; // Enable bit C25 (USB-detect)
351 // Next section configures the key inputs on the LCD data
353 pioptr
->PIO_PER
= 0x0000003BL
; // Enable bits 1,3,4,5, 0
354 pioptr
->PIO_OER
= PIO_PC0
; // Set bit 0 output
355 pioptr
->PIO_ODR
= 0x0000003AL
; // Set bits 1, 3, 4, 5 input
356 pioptr
->PIO_PUER
= 0x0000003AL
; // Set bits 1, 3, 4, 5 with pullups
359 pioptr
->PIO_PUER
= PIO_PB5
; // Enable pullup on bit B5 (MENU)
360 pioptr
->PIO_PER
= PIO_PB5
; // Enable bit B5
364 // Enable PCK2 on PB3, This is for testing of Timer 2 working
365 // It will be used as serial data to the Bluetooth module
366 pioptr
->PIO_ABCDSR
[0] |= PIO_PB3
; // Peripheral B
367 pioptr
->PIO_ABCDSR
[1] &= ~PIO_PB3
; // Peripheral B
368 pioptr
->PIO_PDR
= PIO_PB3
; // Assign to peripheral
369 PMC
->PMC_SCER
|= 0x0400 ; // PCK2 enabled
370 PMC
->PMC_PCK
[2] = 2 ; // PCK2 is PLLA
385 #if defined(ROTARY_ENCODER_NAVIGATION)
398 uint8_t temperature
= 0; // Raw temp reading
399 uint8_t maxTemperature
= 0 ; // Raw temp reading
401 void end_bt_tx_interrupt()
403 Uart
*pUart
= BT_USART
;
404 pUart
->UART_IDR
= UART_IDR_TXBUFE
;
405 NVIC_DisableIRQ(UART1_IRQn
) ;
408 uint16_t getCurrent()
410 static uint16_t Current
;
411 static uint32_t Current_sum
;
412 static uint8_t Current_count
;
414 Current_sum
+= anaIn(TX_CURRENT
);
415 if (++Current_count
>= 50) {
416 Current
= Current_sum
/ 5 ;
421 uint32_t current_scale
= 488 + g_eeGeneral
.txCurrentCalibration
;
422 return (current_scale
* Current
) / 8192;
425 #define STICK_LV_GAIN 0x01
426 #define STICK_LH_GAIN 0x02
427 #define STICK_RV_GAIN 0x04
428 #define STICK_RH_GAIN 0x08
430 #define GAIN_LV 0x00080000
431 #define GAIN_LH 0x00000020
432 #define GAIN_RV 0x20000000
433 #define GAIN_RH 0x00000008
435 #define OFF_LV 0x00000200
436 #define OFF_LH 0x00000004
437 #define OFF_RV 0x00004000
438 #define OFF_RH 0x00000002
440 void setSticksGain(uint8_t gains
)
450 if ( gains
& STICK_LV_GAIN
) {
454 if ( gains
& STICK_LH_GAIN
) {
458 if ( gains
& STICK_RV_GAIN
) {
462 if ( gains
& STICK_RH_GAIN
) {
467 padc
->ADC_CGR
= gain
;
468 padc
->ADC_COR
= offset
;
471 void calcConsumption()
473 Current_accumulator
+= Current_analogue
;
474 static uint32_t OneSecTimer
;
475 if (++OneSecTimer
>= 100) {
477 Current_used
+= Current_accumulator
/ 100 ; // milliAmpSeconds (but scaled)
478 Current_accumulator
= 0 ;
482 uint16_t getBatteryVoltage()
484 int32_t instant_vbat
= anaIn(TX_VOLTAGE
); // using filtered ADC value on purpose
485 instant_vbat
= (instant_vbat
+ instant_vbat
*(g_eeGeneral
.txVoltageCalibration
)/128) * 4191;
486 instant_vbat
/= 5530;
487 return (uint16_t)instant_vbat
;