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 <msp430x54x.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 #define BT_PORT_OUT P9OUT 54 #define BT_PORT_SEL P9SEL 55 #define BT_PORT_DIR P9DIR 56 #define BT_PORT_REN P9REN 57 #define BT_PIN_TXD BIT4 58 #define BT_PIN_RXD BIT5 59 60 // RXD P9.5 61 // TXD P9.4 62 // RTS P1.4 63 // CTS P1.3 64 65 void dummy_handler(void){}; 66 67 // rx state 68 static uint16_t bytes_to_read = 0; 69 static uint8_t * rx_buffer_ptr = 0; 70 71 // tx state 72 static uint16_t bytes_to_write = 0; 73 static uint8_t * tx_buffer_ptr = 0; 74 75 // handlers 76 static void (*rx_done_handler)(void) = dummy_handler; 77 static void (*tx_done_handler)(void) = dummy_handler; 78 static void (*cts_irq_handler)(void) = dummy_handler; 79 80 /** 81 * @brief Initializes the serial communications peripheral and GPIO ports 82 * to communicate with the PAN BT .. assuming 16 Mhz CPU 83 * 84 * @param none 85 * 86 * @return none 87 */ 88 void hal_uart_dma_init(void) 89 { 90 BT_PORT_SEL |= BT_PIN_RXD + BT_PIN_TXD; 91 BT_PORT_DIR |= BT_PIN_TXD; 92 BT_PORT_DIR &= ~BT_PIN_RXD; 93 94 // set BT RTS (P1.4) 95 P1SEL &= ~BIT4; // = 0 - I/O 96 P1DIR |= BIT4; // = 1 - Output 97 P1OUT |= BIT4; // = 1 - RTS high -> stop 98 99 // set BT CTS 100 P1SEL &= ~BIT3; // = 0 - I/O 101 P1DIR &= ~BIT3; // = 0 - Input P1DIR |= BIT4; // RTS 102 103 // set BT SHUTDOWN (P8.2) to 1 (active low) 104 P8SEL &= ~BIT2; // = 0 - I/O 105 P8DIR |= BIT2; // = 1 - Output 106 P8OUT |= BIT2; // = 1 - Active low -> ok 107 108 // Enable ACLK to provide 32 kHz clock to Bluetooth module 109 P11SEL |= BIT0; 110 P11DIR |= BIT0; 111 112 // wait for Bluetooth to power up properly after providing 32khz clock 113 waitAboutOneSecond(); 114 115 UCA2CTL1 |= UCSWRST; //Reset State 116 UCA2CTL0 = UCMODE_0; 117 118 UCA2CTL0 &= ~UC7BIT; // 8bit char 119 UCA2CTL1 |= UCSSEL_2; 120 121 UCA2CTL1 &= ~UCSWRST; // continue 122 123 hal_uart_dma_set_baud(115200); 124 } 125 126 /** 127 128 UART used in low-frequency mode 129 In this mode, the maximum USCI baud rate is one-third the UART source clock frequency BRCLK. 130 131 16000000 / 576000 = 277.77 132 16000000 / 115200 = 138.88 133 16000000 / 921600 = 17.36 134 16000000 / 1000000 = 16.00 135 16000000 / 2000000 = 8.00 136 16000000 / 2400000 = 6.66 137 16000000 / 3000000 = 3.33 138 16000000 / 4000000 = 2.00 139 140 */ 141 int hal_uart_dma_set_baud(uint32_t baud){ 142 143 int result = 0; 144 145 UCA2CTL1 |= UCSWRST; //Reset State 146 147 switch (baud){ 148 149 case 4000000: 150 UCA2BR0 = 2; 151 UCA2BR1 = 0; 152 UCA2MCTL= 0 << 1; // + 0.000 153 break; 154 155 case 3000000: 156 UCA2BR0 = 3; 157 UCA2BR1 = 0; 158 UCA2MCTL= 3 << 1; // + 0.375 159 break; 160 161 case 2400000: 162 UCA2BR0 = 6; 163 UCA2BR1 = 0; 164 UCA2MCTL= 5 << 1; // + 0.625 165 break; 166 167 case 2000000: 168 UCA2BR0 = 8; 169 UCA2BR1 = 0; 170 UCA2MCTL= 0 << 1; // + 0.000 171 break; 172 173 case 1000000: 174 UCA2BR0 = 16; 175 UCA2BR1 = 0; 176 UCA2MCTL= 0 << 1; // + 0.000 177 break; 178 179 case 921600: 180 UCA2BR0 = 17; 181 UCA2BR1 = 0; 182 UCA2MCTL= 7 << 1; // 3 << 1; // + 0.375 183 break; 184 185 case 115200: 186 UCA2BR0 = 138; // from family user guide 187 UCA2BR1 = 0; 188 UCA2MCTL= 7 << 1; // + 0.875 189 break; 190 191 case 57600: 192 UCA2BR0 = 21; 193 UCA2BR1 = 1; 194 UCA2MCTL= 7 << 1; // + 0.875 195 break; 196 197 default: 198 result = -1; 199 break; 200 } 201 202 UCA2CTL1 &= ~UCSWRST; // continue 203 204 return result; 205 } 206 207 void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){ 208 rx_done_handler = the_block_handler; 209 } 210 211 void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){ 212 tx_done_handler = the_block_handler; 213 } 214 215 void hal_uart_dma_set_csr_irq_handler( void (*the_irq_handler)(void)){ 216 if (the_irq_handler){ 217 P1IFG = 0; // no IRQ pending 218 P1IV = 0; // no IRQ pending 219 P1IES &= ~BIT3; // IRQ on 0->1 transition 220 P1IE |= BIT3; // enable IRQ for P1.3 221 cts_irq_handler = the_irq_handler; 222 return; 223 } 224 225 P1IE &= ~BIT3; 226 cts_irq_handler = dummy_handler; 227 } 228 229 /**********************************************************************/ 230 /** 231 * @brief Disables the serial communications peripheral and clears the GPIO 232 * settings used to communicate with the BT. 233 * 234 * @param none 235 * 236 * @return none 237 **************************************************************************/ 238 void hal_uart_dma_shutdown(void) { 239 240 UCA2IE &= ~(UCRXIE | UCTXIE); 241 UCA2CTL1 = UCSWRST; //Reset State 242 BT_PORT_SEL &= ~( BT_PIN_RXD + BT_PIN_TXD ); 243 BT_PORT_DIR |= BT_PIN_TXD; 244 BT_PORT_DIR |= BT_PIN_RXD; 245 BT_PORT_OUT &= ~(BT_PIN_TXD + BT_PIN_RXD); 246 } 247 248 void hal_uart_dma_send_block(const uint8_t * data, uint16_t len){ 249 250 // printf("hal_uart_dma_send_block, size %u\n\r", len); 251 252 UCA2IE &= ~UCTXIE ; // disable TX interrupts 253 254 tx_buffer_ptr = (uint8_t *) data; 255 bytes_to_write = len; 256 257 UCA2IE |= UCTXIE; // enable TX interrupts 258 } 259 260 static inline void hal_uart_dma_enable_rx(void){ 261 P1OUT &= ~BIT4; // = 0 - RTS low -> ok 262 } 263 264 static inline void hal_uart_dma_disable_rx(void){ 265 P1OUT |= BIT4; // = 1 - RTS high -> stop 266 } 267 268 void hal_uart_dma_receive_block(uint8_t *buffer, uint16_t len){ 269 // disable RX interrupts 270 UCA2IE &= ~UCRXIE ; 271 272 rx_buffer_ptr = buffer; 273 bytes_to_read = len; 274 275 // check if byte already received 276 int pending = UCA2IFG & UCRXIFG; 277 278 // enable RX interrupts - will trigger ISR below if byte pending 279 UCA2IE |= UCRXIE; 280 281 // if byte was pending, ISR controls RTS 282 if (!pending) { 283 hal_uart_dma_enable_rx(); 284 } 285 } 286 287 void hal_uart_dma_set_sleep(uint8_t sleep){ 288 hal_cpu_set_uart_needed_during_sleep(!sleep); 289 } 290 291 // block-wise "DMA" RX/TX UART driver 292 #ifdef __GNUC__ 293 __attribute__((interrupt(USCI_A2_VECTOR))) 294 #endif 295 #ifdef __IAR_SYSTEMS_ICC__ 296 #pragma vector=USCI_A2_VECTOR 297 __interrupt 298 #endif 299 void usbRxTxISR(void){ 300 301 // find reason 302 switch (UCA2IV){ 303 304 case 2: // RXIFG 305 if (bytes_to_read == 0) { 306 hal_uart_dma_disable_rx(); 307 UCA2IE &= ~UCRXIE ; // disable RX interrupts 308 return; 309 } 310 *rx_buffer_ptr = UCA2RXBUF; 311 ++rx_buffer_ptr; 312 --bytes_to_read; 313 if (bytes_to_read > 0) { 314 hal_uart_dma_enable_rx(); 315 return; 316 } 317 P1OUT |= BIT4; // = 1 - RTS high -> stop 318 UCA2IE &= ~UCRXIE ; // disable RX interrupts 319 320 (*rx_done_handler)(); 321 322 // force exit low power mode 323 __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU 324 325 break; 326 327 case 4: // TXIFG 328 if (bytes_to_write == 0){ 329 UCA2IE &= ~UCTXIE ; // disable TX interrupts 330 return; 331 } 332 UCA2TXBUF = *tx_buffer_ptr; 333 ++tx_buffer_ptr; 334 --bytes_to_write; 335 336 if (bytes_to_write > 0) { 337 return; 338 } 339 340 UCA2IE &= ~UCTXIE ; // disable TX interrupts 341 342 (*tx_done_handler)(); 343 344 // force exit low power mode 345 __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU 346 347 break; 348 349 default: 350 break; 351 } 352 } 353 354 355 // CTS ISR 356 357 extern void ehcill_handle(uint8_t action); 358 #define EHCILL_CTS_SIGNAL 0x034 359 360 #ifdef __GNUC__ 361 __attribute__((interrupt(PORT1_VECTOR))) 362 #endif 363 #ifdef __IAR_SYSTEMS_ICC__ 364 #pragma vector=PORT1_VECTOR 365 __interrupt 366 #endif 367 void ctsISR(void){ 368 P1IV = 0; 369 (*cts_irq_handler)(); 370 } 371