1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 /** 39 * @file hal_bt.c 40 ***************************************************************************/ 41 #include <stdint.h> 42 43 #include <msp430.h> 44 #include "hal_compat.h" 45 46 #include "hal_uart_dma.h" 47 48 extern void hal_cpu_set_uart_needed_during_sleep(uint8_t enabled); 49 50 // debugging only 51 // #include <stdio.h> 52 53 54 // RXD 3.4 55 // TXD 3.3 56 #define BT_PORT_OUT P3OUT 57 #define BT_PORT_SEL P3SEL 58 #define BT_PORT_DIR P3DIR 59 #define BT_PORT_REN P3REN 60 #define BT_PIN_TXD BIT3 61 #define BT_PIN_RXD BIT4 62 63 // RTS P2.3 64 #define RTS_SEL P2SEL 65 #define RTS_OUT P2OUT 66 #define RTS_DIR P2DIR 67 #define RTS_PIN BIT3 68 69 // CTS P8.1 rewired to P2.6 - only P1 & P2 have interrupts 70 #define CTS_SEL P2SEL 71 #define CTS_OUT P2OUT 72 #define CTS_DIR P2DIR 73 #define CTS_PIN BIT6 74 75 // N_SHUTDOWN P4.1 76 #define N_SHUTDOWN_SEL P4SEL 77 #define N_SHUTDOWN_OUT P4OUT 78 #define N_SHUTDOWN_DIR P4DIR 79 #define N_SHUTDOWN_PIN BIT1 80 81 void dummy_handler(void){}; 82 83 // rx state 84 static uint16_t bytes_to_read = 0; 85 static uint8_t * rx_buffer_ptr = 0; 86 87 // tx state 88 static uint16_t bytes_to_write = 0; 89 static uint8_t * tx_buffer_ptr = 0; 90 91 // handlers 92 static void (*rx_done_handler)(void) = dummy_handler; 93 static void (*tx_done_handler)(void) = dummy_handler; 94 static void (*cts_irq_handler)(void) = dummy_handler; 95 96 /** 97 * @brief Initializes the serial communications peripheral and GPIO ports 98 * to communicate with the PAN BT .. assuming 16 Mhz CPU 99 * 100 * @param none 101 * 102 * @return none 103 */ 104 void hal_uart_dma_init(void) 105 { 106 BT_PORT_SEL |= BT_PIN_RXD + BT_PIN_TXD; 107 BT_PORT_DIR |= BT_PIN_TXD; 108 BT_PORT_DIR &= ~BT_PIN_RXD; 109 110 // set BT RTS 111 RTS_SEL &= ~RTS_PIN; // = 0 - I/O 112 RTS_DIR |= RTS_PIN; // = 1 - Output 113 RTS_OUT |= RTS_PIN; // = 1 - RTS high -> stop 114 115 // set BT CTS 116 CTS_SEL &= ~CTS_PIN; // = 0 - I/O 117 CTS_DIR &= ~CTS_PIN; // = 0 - Input 118 119 // set BT SHUTDOWN to 1 (active low) 120 N_SHUTDOWN_SEL &= ~N_SHUTDOWN_PIN; // = 0 - I/O 121 N_SHUTDOWN_DIR |= N_SHUTDOWN_PIN; // = 1 - Output 122 N_SHUTDOWN_OUT |= N_SHUTDOWN_PIN; // = 1 - Active low -> ok 123 124 // wait for Bluetooth to power up properly after providing 32khz clock 125 waitAboutOneSecond(); 126 127 UCA0CTL1 |= UCSWRST; //Reset State 128 UCA0CTL0 = UCMODE_0; 129 130 UCA0CTL0 &= ~UC7BIT; // 8bit char 131 UCA0CTL1 |= UCSSEL_2; 132 133 UCA0CTL1 &= ~UCSWRST; // continue 134 135 hal_uart_dma_set_baud(115200); 136 } 137 138 /** 139 140 UART used in low-frequency mode 141 In this mode, the maximum USCI baud rate is one-third the UART source clock frequency BRCLK. 142 143 16000000 / 576000 = 277.77 144 16000000 / 115200 = 138.88 145 16000000 / 921600 = 17.36 146 16000000 / 1000000 = 16.00 147 16000000 / 2000000 = 8.00 148 16000000 / 2400000 = 6.66 149 16000000 / 3000000 = 3.33 150 16000000 / 4000000 = 2.00 151 152 */ 153 int hal_uart_dma_set_baud(uint32_t baud){ 154 155 int result = 0; 156 157 UCA0CTL1 |= UCSWRST; //Reset State 158 159 switch (baud){ 160 161 case 4000000: 162 UCA0BR0 = 2; 163 UCA0BR1 = 0; 164 UCA0MCTL= 0 << 1; // + 0.000 165 break; 166 167 case 3000000: 168 UCA0BR0 = 3; 169 UCA0BR1 = 0; 170 UCA0MCTL= 3 << 1; // + 0.375 171 break; 172 173 case 2400000: 174 UCA0BR0 = 6; 175 UCA0BR1 = 0; 176 UCA0MCTL= 5 << 1; // + 0.625 177 break; 178 179 case 2000000: 180 UCA0BR0 = 8; 181 UCA0BR1 = 0; 182 UCA0MCTL= 0 << 1; // + 0.000 183 break; 184 185 case 1000000: 186 UCA0BR0 = 16; 187 UCA0BR1 = 0; 188 UCA0MCTL= 0 << 1; // + 0.000 189 break; 190 191 case 921600: 192 UCA0BR0 = 17; 193 UCA0BR1 = 0; 194 UCA0MCTL= 7 << 1; // 3 << 1; // + 0.375 195 break; 196 197 case 115200: 198 UCA0BR0 = 138; // from family user guide 199 UCA0BR1 = 0; 200 UCA0MCTL= 7 << 1; // + 0.875 201 break; 202 203 case 57600: 204 UCA0BR0 = 21; 205 UCA0BR1 = 1; 206 UCA0MCTL= 7 << 1; // + 0.875 207 break; 208 209 default: 210 result = -1; 211 break; 212 } 213 214 UCA0CTL1 &= ~UCSWRST; // continue 215 216 return result; 217 } 218 219 void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){ 220 rx_done_handler = the_block_handler; 221 } 222 223 void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){ 224 tx_done_handler = the_block_handler; 225 } 226 227 void hal_uart_dma_set_csr_irq_handler( void (*the_irq_handler)(void)){ 228 #ifdef HAVE_CTS_IRQ 229 if (the_irq_handler){ 230 P2IFG = 0; // no IRQ pending 231 P2IV = 0; // no IRQ pending 232 P2IES &= ~ CTS_PIN; // IRQ on 0->1 transition 233 P2IE |= CTS_PIN; // enable IRQ for P8.1 234 cts_irq_handler = the_irq_handler; 235 return; 236 } 237 P2IE &= ~CTS_PIN; 238 cts_irq_handler = dummy_handler; 239 #endif 240 } 241 242 /**********************************************************************/ 243 /** 244 * @brief Disables the serial communications peripheral and clears the GPIO 245 * settings used to communicate with the BT. 246 * 247 * @param none 248 * 249 * @return none 250 **************************************************************************/ 251 void hal_uart_dma_shutdown(void) { 252 253 UCA0IE &= ~(UCRXIE | UCTXIE); 254 UCA0CTL1 = UCSWRST; //Reset State 255 BT_PORT_SEL &= ~( BT_PIN_RXD + BT_PIN_TXD ); 256 BT_PORT_DIR |= BT_PIN_TXD; 257 BT_PORT_DIR |= BT_PIN_RXD; 258 BT_PORT_OUT &= ~(BT_PIN_TXD + BT_PIN_RXD); 259 } 260 261 void hal_uart_dma_send_block(const uint8_t * data, uint16_t len){ 262 263 // printf("hal_uart_dma_send_block, size %u\n\r", len); 264 265 UCA0IE &= ~UCTXIE ; // disable TX interrupts 266 267 tx_buffer_ptr = (uint8_t *) data; 268 bytes_to_write = len; 269 270 UCA0IE |= UCTXIE; // enable TX interrupts 271 } 272 273 static inline void hal_uart_dma_enable_rx(void){ 274 RTS_OUT &= ~ RTS_PIN; // = 0 - RTS low -> ok 275 } 276 277 static inline void hal_uart_dma_disable_rx(void){ 278 RTS_OUT |= RTS_PIN; // = 1 - RTS high -> stop 279 } 280 281 void hal_uart_dma_receive_block(uint8_t *buffer, uint16_t len){ 282 // disable RX interrupts 283 UCA0IE &= ~UCRXIE; 284 285 rx_buffer_ptr = buffer; 286 bytes_to_read = len; 287 288 // check if byte already received 289 int pending = UCA0IFG & UCRXIFG; 290 291 // enable RX interrupts - will trigger ISR below if byte pending 292 UCA0IE |= UCRXIE; // enable RX interrupts 293 294 // if byte was pending, ISR controls RTS 295 if (!pending) { 296 hal_uart_dma_enable_rx(); 297 } 298 } 299 300 void hal_uart_dma_set_sleep(uint8_t sleep){ 301 hal_cpu_set_uart_needed_during_sleep(!sleep); 302 } 303 304 // block-wise "DMA" RX/TX UART driver 305 #ifdef __GNUC__ 306 __attribute__((interrupt(USCI_A0_VECTOR))) 307 #endif 308 #ifdef __IAR_SYSTEMS_ICC__ 309 #pragma vector=USCI_A0_VECTOR 310 __interrupt 311 #endif 312 void usbRxTxISR(void){ 313 314 // find reason 315 switch (UCA0IV){ 316 317 case 2: // RXIFG 318 if (bytes_to_read == 0) { 319 hal_uart_dma_disable_rx(); 320 UCA0IE &= ~UCRXIE ; // disable RX interrupts 321 return; 322 } 323 *rx_buffer_ptr = UCA0RXBUF; 324 ++rx_buffer_ptr; 325 --bytes_to_read; 326 if (bytes_to_read > 0) { 327 hal_uart_dma_enable_rx(); 328 return; 329 } 330 RTS_OUT |= RTS_PIN; // = 1 - RTS high -> stop 331 UCA0IE &= ~UCRXIE ; // disable RX interrupts 332 333 (*rx_done_handler)(); 334 335 // force exit low power mode 336 __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU 337 338 break; 339 340 case 4: // TXIFG 341 if (bytes_to_write == 0){ 342 UCA0IE &= ~UCTXIE ; // disable TX interrupts 343 return; 344 } 345 UCA0TXBUF = *tx_buffer_ptr; 346 ++tx_buffer_ptr; 347 --bytes_to_write; 348 349 if (bytes_to_write > 0) { 350 return; 351 } 352 353 UCA0IE &= ~UCTXIE ; // disable TX interrupts 354 355 (*tx_done_handler)(); 356 357 // force exit low power mode 358 __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU 359 360 break; 361 362 default: 363 break; 364 } 365 } 366 367 368 // CTS ISR 369 #ifdef HAVE_CTS_IRQ 370 // TODO: there's no PORT8_VECTOR, but configuration seems possible 371 372 extern void ehcill_handle(uint8_t action); 373 #define EHCILL_CTS_SIGNAL 0x034 374 375 #ifdef __GNUC__ 376 __attribute__((interrupt(PORT2_VECTOR))) 377 #elif defined( __IAR_SYSTEMS_ICC__) 378 #pragma vector=PORT2_VECTOR 379 __interrupt 380 #endif 381 void ctsISR(void){ 382 P2IV = 0; 383 (*cts_irq_handler)(); 384 } 385 #endif 386 387