Fix ar9x compile/boot (#7102)
[opentx.git] / radio / src / targets / sky9x / board.cpp
blob2bc6e0225dd4bd1c3a1ba4bbfc43bab66b32c48a
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
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.
21 #include "opentx.h"
23 #if defined(PCBAR9X)
24 #include "i2c_driver.h"
25 #endif
27 uint16_t ResetReason;
28 uint32_t Master_frequency ;
29 volatile uint8_t lcdLock;
30 volatile uint32_t lcdInputs;
32 uint16_t Current_analogue;
33 uint16_t Current_max;
34 uint32_t Current_accumulator;
35 uint32_t Current_used;
37 extern "C" void sam_boot( void ) ;
39 // Prototype
40 // Free pins (PA16 is stock buzzer)
41 // PA23, PA24, PA25, PB7, PB13
42 // PC20, PC21(labelled 17), PC22, PC24
43 // REVB
44 // PA25, use for stock buzzer
45 // PB14, PB6
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;
64 /* Configure PIO */
65 configure_pins( (PIO_PB2 | PIO_PB3), PIN_PERIPHERAL | PIN_INPUT | PIN_PER_A | PIN_PORTB | PIN_NO_PULLUP ) ;
67 /* Configure PMC */
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;
74 /* Configure mode */
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;
87 #if 0
88 pUart->UART_IER = UART_IER_RXRDY ;
89 NVIC_EnableIRQ(UART1_IRQn) ;
90 #endif
93 void UART3_Stop()
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()
104 Tc *ptc ;
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
111 ptc->TC_BMR = 2 ;
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()
123 Tc *ptc ;
124 uint32_t timer ;
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
133 ptc->TC_BMR = 0 ;
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 ;
144 void interrupt5ms()
146 static uint32_t pre_scale ; // Used to get 10 Hz counter
148 HAPTIC_HEARTBEAT();
150 if ( ++pre_scale >= 2 ) {
151 BUZZER_HEARTBEAT();
152 pre_scale = 0 ;
153 per10ms();
157 extern "C" void TC2_IRQHandler()
159 uint32_t dummy;
161 /* Clear status bit to acknowledge interrupt */
162 dummy = TC0->TC_CHANNEL[2].TC_SR;
163 (void) dummy ; // Discard value - prevents compiler warning
165 interrupt5ms();
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)
177 // REVB board:
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
182 void init_pwm()
184 Pwm *pwmptr ;
185 uint32_t timer ;
187 PMC->PMC_PCER0 |= ( 1 << ID_PWM ) ; // Enable peripheral clock to PWM
189 MATRIX->CCFG_SYSIO |= 0x00000020L ; // Disable TDO let PB5 work!
191 /* Configure PIO */
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 ;
202 pwmptr = PWM ;
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
224 // LCD i/o pins
225 // LCD_RES PC27
226 // LCD_CS1 PC26
227 // LCD_E PC12
228 // LCD_RnW PC13
229 // LCD_A0 PC15
230 // LCD_D0 PC0
231 // LCD_D1 PC7
232 // LCD_D2 PC6
233 // LCD_D3 PC5
234 // LCD_D4 PC4
235 // LCD_D5 PC3
236 // LCD_D6 PC2
237 // LCD_D7 PC1
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 )
248 Pio * pioptr;
250 pioptr = PIOA + ((config & PIN_PORT_MASK) >> 6);
251 if (config & PIN_PULLUP) {
252 pioptr->PIO_PPDDR = pins;
253 pioptr->PIO_PUER = pins;
255 else {
256 pioptr->PIO_PUDR = pins;
259 if (config & PIN_PULLDOWN) {
260 pioptr->PIO_PUDR = pins;
261 pioptr->PIO_PPDER = pins;
263 else {
264 pioptr->PIO_PPDDR = pins;
267 if (config & PIN_HIGH) {
268 pioptr->PIO_SODR = pins;
270 else {
271 pioptr->PIO_CODR = pins;
274 if (config & PIN_INPUT) {
275 pioptr->PIO_ODR = pins;
277 else {
278 pioptr->PIO_OER = pins;
281 if (config & PIN_PERI_MASK_L) {
282 pioptr->PIO_ABCDSR[0] |= pins;
284 else {
285 pioptr->PIO_ABCDSR[0] &= ~pins;
288 if (config & PIN_PERI_MASK_H) {
289 pioptr->PIO_ABCDSR[1] |= pins;
291 else {
292 pioptr->PIO_ABCDSR[1] &= ~pins;
295 if (config & PIN_ENABLE) {
296 pioptr->PIO_PER = pins;
298 else {
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)
308 void i2cInit()
310 Pio *pioptr;
311 uint32_t timing;
313 PMC->PMC_PCER0 |= 0x00080000L ; // Enable peripheral clock to TWI0
315 TWI0->TWI_CR = TWI_CR_SWRST ; // Reset in case we are restarting
317 /* Configure PIO */
318 pioptr = PIOA ;
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
324 timing += 15 - 4 ;
325 timing /= 16 ;
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) ;
333 #endif
335 void boardInit()
337 Pio *pioptr ;
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)
347 pwrInit() ;
349 config_free_pins() ;
351 // Next section configures the key inputs on the LCD data
352 pioptr = PIOC;
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
358 pioptr = PIOB ;
359 pioptr->PIO_PUER = PIO_PB5 ; // Enable pullup on bit B5 (MENU)
360 pioptr->PIO_PER = PIO_PB5 ; // Enable bit B5
362 setup_switches() ;
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
372 start_timer2() ;
373 start_timer0() ;
374 adcInit() ;
375 init_pwm() ;
377 __enable_irq();
379 audioInit();
381 i2cInit();
383 eepromInit();
385 #if defined(ROTARY_ENCODER_NAVIGATION)
386 rotaryEncoderInit();
387 #endif
389 lcdInit();
391 init_SDcard();
393 #if defined(PCBAR9X)
394 rtcInit();
395 #endif
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 ;
417 Current_sum = 0 ;
418 Current_count = 0 ;
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)
442 Adc *padc ;
443 uint32_t gain ;
444 uint32_t offset ;
446 gain = 0 ;
447 offset = 0 ;
448 padc = ADC ;
450 if ( gains & STICK_LV_GAIN ) {
451 gain |= GAIN_LV ;
452 offset |= OFF_LV ;
454 if ( gains & STICK_LH_GAIN ) {
455 gain |= GAIN_LH ;
456 offset |= OFF_LH ;
458 if ( gains & STICK_RV_GAIN ) {
459 gain |= GAIN_RV ;
460 offset |= OFF_RV ;
462 if ( gains & STICK_RH_GAIN ) {
463 gain |= GAIN_RH ;
464 offset |= OFF_RH ;
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) {
476 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;
490 void boardOff()
492 pwrOff();