mirror of
https://github.com/elua/elua.git
synced 2025-01-25 01:02:54 +08:00
AVR32 system timer implementation
This commit is contained in:
parent
356e683e3a
commit
bed235ccdd
@ -33,7 +33,6 @@
|
||||
//#define CON_UART_ID ( SERMUX_SERVICE_ID_FIRST + 1 )
|
||||
#define CON_UART_ID 0
|
||||
#define CON_UART_SPEED 115200
|
||||
#define CON_TIMER_ID 0
|
||||
#define TERM_LINES 25
|
||||
#define TERM_COLS 80
|
||||
|
||||
@ -116,7 +115,7 @@
|
||||
#else
|
||||
#define NUM_TIMER 3
|
||||
#endif
|
||||
#define NUM_PWM 7
|
||||
#define NUM_PWM 6
|
||||
#define NUM_I2C 1
|
||||
#define NUM_ADC 8
|
||||
#define NUM_CAN 0
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
#define CON_UART_ID 1
|
||||
#define CON_UART_SPEED 115200
|
||||
#define CON_TIMER_ID 0
|
||||
#define TERM_LINES 25
|
||||
#define TERM_COLS 80
|
||||
|
||||
@ -86,7 +85,7 @@
|
||||
#else
|
||||
#define NUM_TIMER 3
|
||||
#endif
|
||||
#define NUM_PWM 7
|
||||
#define NUM_PWM 6
|
||||
#define NUM_ADC 8
|
||||
#define NUM_CAN 0
|
||||
|
||||
|
@ -61,7 +61,6 @@
|
||||
# define CON_UART_ID 0
|
||||
#endif
|
||||
#define CON_UART_SPEED 115200
|
||||
#define CON_TIMER_ID 0
|
||||
#define TERM_LINES 25
|
||||
#define TERM_COLS 80
|
||||
|
||||
@ -163,7 +162,7 @@
|
||||
#else
|
||||
#define NUM_TIMER 3
|
||||
#endif
|
||||
#define NUM_PWM 7 // PWM7 is on GPIO50
|
||||
#define NUM_PWM 6 // PWM7 is on GPIO50
|
||||
#define NUM_I2C 1
|
||||
#define NUM_ADC 8 // Though ADC3 pin is the Ethernet IRQ
|
||||
#define NUM_CAN 0
|
||||
|
@ -57,6 +57,54 @@ static int eth_timer_fired;
|
||||
|
||||
#endif // BUILD_UIP
|
||||
|
||||
// ****************************************************************************
|
||||
// AVR32 system timer implementation
|
||||
|
||||
// Since the timer hardware (TC) on the AVR32 is pretty basic (16-bit timers,
|
||||
// limited prescaling options) we'll be using the PWM subsystem for the system
|
||||
// timer. The PWM hardware has much better prescaling options and it uses 20-bit
|
||||
// timers which are perfect for our needs. As a bonus, each PWM channel can be
|
||||
// clocked from two independent linear prescalers (CLKA and CLKB). The AVR32
|
||||
// PWM driver (pwm.c) uses only CLKA and disables CLKB, so by using CLKB we
|
||||
// won't change the regular PWM behaviour. The only downside is that we'll steal
|
||||
// a PWM channel for the system timer.
|
||||
|
||||
#define SYSTIMER_PWM_CH 6
|
||||
|
||||
__attribute__((__interrupt__)) static void systimer_int_handler()
|
||||
{
|
||||
volatile u32 dummy = AVR32_PWM.isr; // clear interrupt
|
||||
|
||||
( void )dummy;
|
||||
cmn_systimer_periodic();
|
||||
}
|
||||
|
||||
static void platform_systimer_init()
|
||||
{
|
||||
avr32_pwm_mr_t mr = AVR32_PWM.MR;
|
||||
|
||||
// Set CLKB prescaler for 1MHz clock (which is exactly our system clock frequency)
|
||||
mr.preb = 0; // main source clock is MCK (PBA)
|
||||
mr.divb = REQ_PBA_FREQ / 1000000; // set CLKB to 1MHz
|
||||
AVR32_PWM.MR = mr;
|
||||
|
||||
// Now setup our PWM channel
|
||||
// Clock from CLKB, left aligned (the other parameters are not important)
|
||||
AVR32_PWM.channel[ SYSTIMER_PWM_CH ].cmr = AVR32_PWM_CMR_CPRE_CLKB;
|
||||
// The period register is 20-bit wide (1048576). We set it so we get interrupts
|
||||
// every second (which results in a very reasonable system load)
|
||||
AVR32_PWM.channel[ SYSTIMER_PWM_CH ].cprd = 1000000;
|
||||
// The duty cycle is arbitrary set to 50%
|
||||
AVR32_PWM.channel[ SYSTIMER_PWM_CH ].cdty = 500000;
|
||||
|
||||
// Setup PWM interrupt
|
||||
INTC_register_interrupt( &systimer_int_handler, AVR32_PWM_IRQ, AVR32_INTC_INT0 );
|
||||
AVR32_PWM.ier = 1 << SYSTIMER_PWM_CH;
|
||||
|
||||
// Enable the channel
|
||||
AVR32_PWM.ena = 1 << SYSTIMER_PWM_CH;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Platform initialization
|
||||
#ifdef BUILD_UIP
|
||||
@ -233,7 +281,6 @@ int platform_init()
|
||||
pwm_init();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef BUILD_UIP
|
||||
platform_ethernet_setup();
|
||||
#endif
|
||||
@ -248,6 +295,12 @@ int platform_init()
|
||||
platform_pio_op( 0, ( pio_type )1 << 0 , PLATFORM_IO_PIN_PULLUP );
|
||||
#endif
|
||||
|
||||
// Setup system timer
|
||||
// NOTE: this MUST come AFTER pwm_init!
|
||||
cmn_systimer_set_base_freq( 1000000 );
|
||||
cmn_systimer_set_interrupt_freq( 1 );
|
||||
platform_systimer_init();
|
||||
|
||||
cmn_platform_init();
|
||||
|
||||
// All done
|
||||
@ -399,7 +452,7 @@ void platform_s_uart_send( unsigned id, u8 data )
|
||||
pusart->thr = ( data << AVR32_USART_THR_TXCHR_OFFSET ) & AVR32_USART_THR_TXCHR_MASK;
|
||||
}
|
||||
|
||||
int platform_s_uart_recv( unsigned id, s32 timeout )
|
||||
int platform_s_uart_recv( unsigned id, timer_data_type timeout )
|
||||
{
|
||||
volatile avr32_usart_t *pusart = ( volatile avr32_usart_t* )uart_base_addr[ id ];
|
||||
int temp;
|
||||
@ -529,7 +582,7 @@ static u32 platform_timer_set_clock( unsigned id, u32 clock )
|
||||
#endif
|
||||
}
|
||||
|
||||
void platform_s_timer_delay( unsigned id, u32 delay_us )
|
||||
void platform_s_timer_delay( unsigned id, timer_data_type delay_us )
|
||||
{
|
||||
volatile avr32_tc_t *tc = &AVR32_TC;
|
||||
u32 freq;
|
||||
@ -547,7 +600,7 @@ void platform_s_timer_delay( unsigned id, u32 delay_us )
|
||||
while( ( tc_read_tc( tc, id ) < final ) && !sr->covfs );
|
||||
}
|
||||
|
||||
u32 platform_s_timer_op( unsigned id, int op, u32 data )
|
||||
timer_data_type platform_s_timer_op( unsigned id, int op, timer_data_type data )
|
||||
{
|
||||
u32 res = 0;
|
||||
volatile int i;
|
||||
@ -580,15 +633,39 @@ u32 platform_s_timer_op( unsigned id, int op, u32 data )
|
||||
case PLATFORM_TIMER_OP_GET_CLOCK:
|
||||
res = platform_timer_get_clock( id );
|
||||
break;
|
||||
|
||||
case PLATFORM_TIMER_OP_GET_MAX_CNT:
|
||||
res = 0xFFFF;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int platform_s_timer_set_match_int( unsigned id, u32 period_us, int type )
|
||||
int platform_s_timer_set_match_int( unsigned id, timer_data_type period_us, int type )
|
||||
{
|
||||
return PLATFORM_TIMER_INT_INVALID_ID;
|
||||
}
|
||||
|
||||
u64 platform_timer_sys_raw_read()
|
||||
{
|
||||
return AVR32_PWM.channel[ SYSTIMER_PWM_CH ].ccnt;
|
||||
}
|
||||
|
||||
void platform_timer_sys_stop()
|
||||
{
|
||||
AVR32_PWM.dis = 1 << SYSTIMER_PWM_CH;
|
||||
}
|
||||
|
||||
void platform_timer_sys_start()
|
||||
{
|
||||
AVR32_PWM.ena = 1 << SYSTIMER_PWM_CH;
|
||||
}
|
||||
|
||||
timer_data_type platform_timer_read_sys()
|
||||
{
|
||||
return cmn_systimer_get();
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// SPI functions
|
||||
|
||||
@ -829,6 +906,11 @@ int platform_adc_start_sequence( )
|
||||
|
||||
#if NUM_PWM > 0
|
||||
|
||||
// One PWM channel is used by the AVR32 system timer (look at the start of this
|
||||
// file for more information). Currently this channel is hardcoded in platform.c
|
||||
// (SYSTIMER_PWM_CH) to 6. If this is not convenient feel free to move the
|
||||
// definition of SYSTIMER_PWM_CH in platform_conf.h and select another PWM channel,
|
||||
// BUT remember to modify the below PWM pin mapping accordingly!
|
||||
static const gpio_map_t pwm_pins =
|
||||
{
|
||||
#if ( BOARD == ATEVK1100 ) || ( BOARD == MIZAR32 )
|
||||
@ -838,7 +920,7 @@ static const gpio_map_t pwm_pins =
|
||||
{ AVR32_PWM_3_PIN, AVR32_PWM_3_FUNCTION }, // PB22 - LED7
|
||||
{ AVR32_PWM_4_1_PIN, AVR32_PWM_4_1_FUNCTION }, // PB27 - LED0
|
||||
{ AVR32_PWM_5_1_PIN, AVR32_PWM_5_1_FUNCTION }, // PB28 - LED1
|
||||
{ AVR32_PWM_6_PIN, AVR32_PWM_6_FUNCTION }, // PB18 - LCD_C / GPIO50
|
||||
// { AVR32_PWM_6_PIN, AVR32_PWM_6_FUNCTION }, // PB18 - LCD_C / GPIO50
|
||||
#elif BOARD == ATEVK1101
|
||||
{ AVR32_PWM_0_0_PIN, AVR32_PWM_0_0_FUNCTION }, // PA7 LED0
|
||||
{ AVR32_PWM_1_0_PIN, AVR32_PWM_1_0_FUNCTION }, // PA8 LED1
|
||||
@ -846,7 +928,7 @@ static const gpio_map_t pwm_pins =
|
||||
{ AVR32_PWM_3_0_PIN, AVR32_PWM_3_0_FUNCTION }, // PA14 ? or _1 PA25
|
||||
{ AVR32_PWM_4_1_PIN, AVR32_PWM_4_1_FUNCTION }, // PA28 - audio out
|
||||
{ AVR32_PWM_5_1_PIN, AVR32_PWM_5_1_FUNCTION }, // PB5: UART1-RTS & Nexus i/f EVTIn / _0 PA18=Xin0
|
||||
{ AVR32_PWM_6_0_PIN, AVR32_PWM_6_0_FUNCTION }, // PA22 - LED3 and audio out
|
||||
// { AVR32_PWM_6_0_PIN, AVR32_PWM_6_0_FUNCTION }, // PA22 - LED3 and audio out
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -915,7 +997,7 @@ static void find_clock_configuration( u32 frequency,
|
||||
#define prescalers( n ) ( 1 << n )
|
||||
const unsigned nprescalers = 11;
|
||||
|
||||
unsigned prescaler; // Select a prescaler
|
||||
unsigned prescaler = 0; // Select a prescaler
|
||||
unsigned divisor = 0;
|
||||
|
||||
if ( frequency > REQ_PBA_FREQ )
|
||||
@ -945,7 +1027,6 @@ static void find_clock_configuration( u32 frequency,
|
||||
}
|
||||
#undef prescalers
|
||||
|
||||
|
||||
u32 platform_pwm_set_clock( unsigned id, u32 freq )
|
||||
{
|
||||
unsigned pre, div;
|
||||
|
Loading…
x
Reference in New Issue
Block a user