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 BLUEKITCHEN
24 * GMBH 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
dummy_handler(void)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 */
hal_uart_dma_init(void)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 */
hal_uart_dma_set_baud(uint32_t baud)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
hal_uart_dma_set_block_received(void (* the_block_handler)(void))207 void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){
208 rx_done_handler = the_block_handler;
209 }
210
hal_uart_dma_set_block_sent(void (* the_block_handler)(void))211 void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){
212 tx_done_handler = the_block_handler;
213 }
214
hal_uart_dma_set_csr_irq_handler(void (* the_irq_handler)(void))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 **************************************************************************/
hal_uart_dma_shutdown(void)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
hal_uart_dma_send_block(const uint8_t * data,uint16_t len)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
hal_uart_dma_enable_rx(void)260 static inline void hal_uart_dma_enable_rx(void){
261 P1OUT &= ~BIT4; // = 0 - RTS low -> ok
262 }
263
hal_uart_dma_disable_rx(void)264 static inline void hal_uart_dma_disable_rx(void){
265 P1OUT |= BIT4; // = 1 - RTS high -> stop
266 }
267
hal_uart_dma_receive_block(uint8_t * buffer,uint16_t len)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
hal_uart_dma_set_sleep(uint8_t sleep)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
usbRxTxISR(void)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
ctsISR(void)367 void ctsISR(void){
368 P1IV = 0;
369 (*cts_irq_handler)();
370 }
371