btstack/eZ430-RF2560/src/hal_uart_dma.c
2012-01-14 20:39:59 +00:00

327 lines
8.2 KiB
C
Executable File

/**
* @file hal_bt.c
***************************************************************************/
#include <stdint.h>
#include <msp430x54x.h>
#include "hal_compat.h"
#include <btstack/hal_uart_dma.h>
extern void hal_cpu_set_uart_needed_during_sleep(uint8_t enabled);
// debugging only
// #include <stdio.h>
#define BT_PORT_OUT P9OUT
#define BT_PORT_SEL P9SEL
#define BT_PORT_DIR P9DIR
#define BT_PORT_REN P9REN
#define BT_PIN_TXD BIT4
#define BT_PIN_RXD BIT5
// RXD P9.5
// TXD P9.4
// RTS P1.4
// CTS P1.3
void dummy_handler(void){};
// rx state
static uint16_t bytes_to_read = 0;
static uint8_t * rx_buffer_ptr = 0;
// tx state
static uint16_t bytes_to_write = 0;
static uint8_t * tx_buffer_ptr = 0;
// handlers
static void (*rx_done_handler)(void) = dummy_handler;
static void (*tx_done_handler)(void) = dummy_handler;
static void (*cts_irq_handler)(void) = dummy_handler;
/**
* @brief Initializes the serial communications peripheral and GPIO ports
* to communicate with the PAN BT .. assuming 16 Mhz CPU
*
* @param none
*
* @return none
*/
void hal_uart_dma_init(void)
{
BT_PORT_SEL |= BT_PIN_RXD + BT_PIN_TXD;
BT_PORT_DIR |= BT_PIN_TXD;
BT_PORT_DIR &= ~BT_PIN_RXD;
// set BT RTS (P1.3)
P1SEL &= ~BIT3; // = 0 - I/O
P1DIR |= BIT3; // = 1 - Output
P1OUT |= BIT3; // = 1 - RTS high -> stop
// set BT CTS (P1.4)
P1SEL &= ~BIT4; // = 0 - I/O
P1DIR &= ~BIT4; // = 0 - Input P1DIR |= BIT4; // RTS
// set BT SHUTDOWN (P2.7) to 1 (active low)
P2SEL &= ~BIT7; // = 0 - I/O
P2DIR |= BIT7; // = 1 - Output
P2OUT |= BIT7; // = 1 - Active low -> ok
// Enable ACLK to provide 32 kHz clock to Bluetooth module
P2SEL |= BIT6;
P2DIR |= BIT6;
// wait for Bluetooth to power up properly after providing 32khz clock
waitAboutOneSecond();
UCA2CTL1 |= UCSWRST; //Reset State
UCA2CTL0 = UCMODE_0;
UCA2CTL0 &= ~UC7BIT; // 8bit char
UCA2CTL1 |= UCSSEL_2;
UCA2CTL1 &= ~UCSWRST; // continue
hal_uart_dma_set_baud(115200);
}
/**
UART used in low-frequency mode
In this mode, the maximum USCI baud rate is one-third the UART source clock frequency BRCLK.
16000000 / 576000 = 277.77
16000000 / 115200 = 138.88
16000000 / 921600 = 17.36
16000000 / 1000000 = 16.00
16000000 / 2000000 = 8.00
16000000 / 2400000 = 6.66
16000000 / 3000000 = 3.33
16000000 / 4000000 = 2.00
*/
int hal_uart_dma_set_baud(uint32_t baud){
int result = 0;
UCA2CTL1 |= UCSWRST; //Reset State
switch (baud){
case 4000000:
UCA2BR0 = 2;
UCA2BR1 = 0;
UCA2MCTL= 0 << 1; // + 0.000
break;
case 3000000:
UCA2BR0 = 3;
UCA2BR1 = 0;
UCA2MCTL= 3 << 1; // + 0.375
break;
case 2400000:
UCA2BR0 = 6;
UCA2BR1 = 0;
UCA2MCTL= 5 << 1; // + 0.625
break;
case 2000000:
UCA2BR0 = 8;
UCA2BR1 = 0;
UCA2MCTL= 0 << 1; // + 0.000
break;
case 1000000:
UCA2BR0 = 16;
UCA2BR1 = 0;
UCA2MCTL= 0 << 1; // + 0.000
break;
case 921600:
UCA2BR0 = 17;
UCA2BR1 = 0;
UCA2MCTL= 7 << 1; // 3 << 1; // + 0.375
break;
case 115200:
UCA2BR0 = 138; // from family user guide
UCA2BR1 = 0;
UCA2MCTL= 7 << 1; // + 0.875
break;
case 57600:
UCA2BR0 = 21;
UCA2BR1 = 1;
UCA2MCTL= 7 << 1; // + 0.875
break;
default:
result = -1;
break;
}
UCA2CTL1 &= ~UCSWRST; // continue
return result;
}
void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){
rx_done_handler = the_block_handler;
}
void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){
tx_done_handler = the_block_handler;
}
void hal_uart_dma_set_csr_irq_handler( void (*the_irq_handler)(void)){
if (the_irq_handler){
P1IFG = 0; // no IRQ pending
P1IV = 0; // no IRQ pending
P1IES &= ~BIT4; // IRQ on 0->1 transition
P1IE |= BIT4; // enable IRQ for P1.3
cts_irq_handler = the_irq_handler;
return;
}
P1IE &= ~BIT4;
cts_irq_handler = dummy_handler;
}
/**********************************************************************/
/**
* @brief Disables the serial communications peripheral and clears the GPIO
* settings used to communicate with the BT.
*
* @param none
*
* @return none
**************************************************************************/
void hal_uart_dma_shutdown(void) {
UCA2IE &= ~(UCRXIE | UCTXIE);
UCA2CTL1 = UCSWRST; //Reset State
BT_PORT_SEL &= ~( BT_PIN_RXD + BT_PIN_TXD );
BT_PORT_DIR |= BT_PIN_TXD;
BT_PORT_DIR |= BT_PIN_RXD;
BT_PORT_OUT &= ~(BT_PIN_TXD + BT_PIN_RXD);
}
void hal_uart_dma_send_block(const uint8_t * data, uint16_t len){
// printf("hal_uart_dma_send_block, size %u\n\r", len);
UCA2IE &= ~UCTXIE ; // disable TX interrupts
tx_buffer_ptr = (uint8_t *) data;
bytes_to_write = len;
UCA2IE |= UCTXIE; // enable TX interrupts
}
static inline void hal_uart_dma_enable_rx(void){
P1OUT &= ~BIT3; // = 0 - RTS low -> ok
}
static inline void hal_uart_dma_disable_rx(void){
P1OUT |= BIT3; // = 1 - RTS high -> stop
}
// int used to indicate a request for more new data
void hal_uart_dma_receive_block(uint8_t *buffer, uint16_t len){
UCA2IE &= ~UCRXIE ; // disable RX interrupts
rx_buffer_ptr = buffer;
bytes_to_read = len;
UCA2IE |= UCRXIE; // enable RX interrupts
hal_uart_dma_enable_rx(); // enable receive
}
void hal_uart_dma_set_sleep(uint8_t sleep){
hal_cpu_set_uart_needed_during_sleep(!sleep);
}
// block-wise "DMA" RX/TX UART driver
#ifdef __GNUC__
__attribute__((interrupt(USCI_A2_VECTOR)))
#endif
#ifdef __IAR_SYSTEMS_ICC__
#pragma vector=USCI_A2_VECTOR
__interrupt
#endif
void usbRxTxISR(void){
// find reason
switch (UCA2IV){
case 2: // RXIFG
if (bytes_to_read == 0) {
hal_uart_dma_disable_rx();
UCA2IE &= ~UCRXIE ; // disable RX interrupts
return;
}
*rx_buffer_ptr = UCA2RXBUF;
++rx_buffer_ptr;
--bytes_to_read;
if (bytes_to_read > 0) {
return;
}
P1OUT |= BIT3; // = 1 - RTS high -> stop
UCA2IE &= ~UCRXIE ; // disable RX interrupts
(*rx_done_handler)();
// force exit low power mode
__bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
break;
case 4: // TXIFG
if (bytes_to_write == 0){
UCA2IE &= ~UCTXIE ; // disable TX interrupts
return;
}
UCA2TXBUF = *tx_buffer_ptr;
++tx_buffer_ptr;
--bytes_to_write;
if (bytes_to_write > 0) {
return;
}
UCA2IE &= ~UCTXIE ; // disable TX interrupts
(*tx_done_handler)();
// force exit low power mode
__bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
break;
default:
break;
}
}
// CTS ISR
extern void ehcill_handle(uint8_t action);
#define EHCILL_CTS_SIGNAL 0x034
#ifdef __GNUC__
__attribute__((interrupt(PORT1_VECTOR)))
#endif
#ifdef __IAR_SYSTEMS_ICC__
#pragma vector=PORT1_VECTOR
__interrupt
#endif
void ctsISR(void){
P1IV = 0;
(*cts_irq_handler)();
}