xref: /btstack/port/archive/msp-exp430f5438-cc2564b/src/hal_uart_dma.c (revision 2fca4dad957cd7b88f4657ed51e89c12615dda72)
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