1 /*!
2 * \file lr1110mb1xxs-board.c
3 *
4 * \brief Target board LR1110MB1XXS shield driver implementation
5 *
6 * \copyright Revised BSD License, see section \ref LICENSE.
7 *
8 * \code
9 * ______ _
10 * / _____) _ | |
11 * ( (____ _____ ____ _| |_ _____ ____| |__
12 * \____ \| ___ | (_ _) ___ |/ ___) _ \
13 * _____) ) ____| | | || |_| ____( (___| | | |
14 * (______/|_____)_|_|_| \__)_____)\____)_| |_|
15 * (C)2019-2019 Semtech
16 *
17 * \endcode
18 *
19 */
20 #include <stdlib.h>
21 #include "utilities.h"
22 #include "board-config.h"
23 #include "delay.h"
24 #include "rtc-board.h"
25 #include "radio.h"
26
27 #include "lr1110_hal.h"
28 #include "lr1110_radio.h"
29 #include "lr1110_system.h"
30 #include "lr1110_regmem.h"
31
32 #include "lr1110-board.h"
33
34 #define LR1110_SHIELD_HAS_TCXO 1
35
36 #if( LR1110_SHIELD_HAS_TCXO == 1 )
37 #undef BOARD_TCXO_WAKEUP_TIME
38 #define BOARD_TCXO_WAKEUP_TIME 5 // 5 milliseconds
39 #endif
40
41 /*!
42 * Debug GPIO pins objects
43 */
44 #if defined( USE_RADIO_DEBUG )
45 Gpio_t DbgPinTx;
46 Gpio_t DbgPinRx;
47 #endif
48
49 static void lr1110_board_init_tcxo_io( const void* context );
50
lr1110_board_init_io(const void * context)51 void lr1110_board_init_io( const void* context )
52 {
53 GpioInit( &( ( lr1110_t* ) context )->reset, RADIO_RESET, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
54 GpioInit( &( ( lr1110_t* ) context )->spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
55 GpioInit( &( ( lr1110_t* ) context )->dio_1, RADIO_DIO_1, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
56 GpioInit( &( ( lr1110_t* ) context )->busy, RADIO_BUSY, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
57 }
58
lr1110_board_deinit_io(const void * context)59 void lr1110_board_deinit_io( const void* context )
60 {
61 GpioInit( &( ( lr1110_t* ) context )->reset, RADIO_RESET, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
62 GpioInit( &( ( lr1110_t* ) context )->spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
63 GpioInit( &( ( lr1110_t* ) context )->dio_1, RADIO_DIO_1, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
64 GpioInit( &( ( lr1110_t* ) context )->busy, RADIO_BUSY, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
65 }
66
lr1110_board_init_dbg_io(const void * context)67 void lr1110_board_init_dbg_io( const void* context )
68 {
69 #if defined( USE_RADIO_DEBUG )
70 GpioInit( &DbgPinTx, RADIO_DBG_PIN_TX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
71 GpioInit( &DbgPinRx, RADIO_DBG_PIN_RX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
72 #endif
73 }
74
lr1110_board_set_rf_tx_power(const void * context,int8_t power)75 void lr1110_board_set_rf_tx_power( const void* context, int8_t power )
76 {
77 // TODO: Add PA Config check
78 if( power > 0 )
79 {
80 if( power > 22 )
81 {
82 power = 22;
83 }
84 }
85 else
86 {
87 if( power < -9 )
88 {
89 power = -9;
90 }
91 }
92 lr1110_radio_set_tx_params( context, power, LR1110_RADIO_RAMP_TIME_40U );
93 }
94
lr1110_board_get_tcxo_wakeup_time(const void * context)95 uint32_t lr1110_board_get_tcxo_wakeup_time( const void* context )
96 {
97 return BOARD_TCXO_WAKEUP_TIME;
98 }
99
lr1110_get_dio_1_pin_state(const void * context)100 uint32_t lr1110_get_dio_1_pin_state( const void* context )
101 {
102 return GpioRead( &( ( lr1110_t* ) context )->dio_1 );
103 }
104
lr1110_board_init(const void * context,lr1110_dio_irq_handler dio_irq)105 void lr1110_board_init( const void* context, lr1110_dio_irq_handler dio_irq )
106 {
107 lr1110_system_reset( context );
108 lr1110_hal_set_operating_mode( context, LR1110_HAL_OP_MODE_STDBY_RC );
109
110 // Attach interrupt handler to radio irq pin
111 GpioSetInterrupt( &( ( lr1110_t* ) context )->dio_1, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, dio_irq );
112
113 lr1110_system_stat1_t stat1;
114 lr1110_system_stat2_t stat2;
115 uint32_t irq = 0;
116 lr1110_system_get_status( context, &stat1, &stat2, &irq );
117 lr1110_system_version_t version;
118 lr1110_system_get_version( context, &version );
119 lr1110_system_errors_t errors = { 0 };
120 lr1110_system_get_errors( context, &errors );
121 lr1110_system_clear_errors( context );
122
123 // Initialize TCXO control
124 lr1110_board_init_tcxo_io( context );
125
126 // Initialize RF switch control
127 lr1110_system_rfswitch_config_t rf_switch_configuration;
128 rf_switch_configuration.enable = LR1110_SYSTEM_RFSW0_HIGH | LR1110_SYSTEM_RFSW1_HIGH;
129 rf_switch_configuration.standby = 0;
130 rf_switch_configuration.rx = LR1110_SYSTEM_RFSW0_HIGH;
131 rf_switch_configuration.tx = LR1110_SYSTEM_RFSW0_HIGH | LR1110_SYSTEM_RFSW1_HIGH;
132 rf_switch_configuration.wifi = 0;
133 rf_switch_configuration.gnss = 0;
134
135 lr1110_system_set_dio_as_rf_switch( context, &rf_switch_configuration );
136
137 lr1110_radio_pa_config_t paConfig = {
138 .pa_sel = LR1110_RADIO_PA_SEL_LP,
139 .pa_reg_supply = LR1110_RADIO_PA_REG_SUPPLY_DCDC,
140 .pa_dutycycle = 0x04,
141 .pa_hp_sel = 0x00,
142 };
143 lr1110_radio_set_pa_config( context, &paConfig );
144
145 // Set packet type
146 lr1110_radio_packet_types_t packet_type = LR1110_RADIO_PACKET_LORA;
147 lr1110_radio_set_packet_type( context, packet_type );
148 }
149
lr1110_board_init_tcxo_io(const void * context)150 static void lr1110_board_init_tcxo_io( const void* context )
151 {
152 #if( LR1110_SHIELD_HAS_TCXO == 1 )
153 lr1110_system_set_tcxo_mode( context, LR1110_SYSTEM_TCXO_SUPPLY_VOLTAGE_1_8V,
154 ( lr1110_board_get_tcxo_wakeup_time( context ) * 1000 ) / 30.52 );
155
156 uint8_t calib_params = LR1110_SYSTEM_CALIBRATE_LF_RC_MASK | LR1110_SYSTEM_CALIBRATE_HF_RC_MASK |
157 LR1110_SYSTEM_CALIBRATE_PLL_MASK | LR1110_SYSTEM_CALIBRATE_ADC_MASK |
158 LR1110_SYSTEM_CALIBRATE_IMG_MASK | LR1110_SYSTEM_CALIBRATE_PLL_TX_MASK;
159 lr1110_system_calibrate( context, calib_params );
160 #endif
161 }
162
163 //
164 // lr1110_hal.h API implementation
165 //
166
167 static lr1110_hal_status_t lr1110_hal_wait_on_busy( const void* context );
168
lr1110_hal_write(const void * context,const uint8_t * command,const uint16_t command_length,const uint8_t * data,const uint16_t data_length)169 lr1110_hal_status_t lr1110_hal_write( const void* context, const uint8_t* command, const uint16_t command_length,
170 const uint8_t* data, const uint16_t data_length )
171
172 {
173 if( lr1110_hal_wakeup( context ) == LR1110_HAL_STATUS_OK )
174 {
175 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 0 );
176 for( uint16_t i = 0; i < command_length; i++ )
177 {
178 SpiInOut( &( ( lr1110_t* ) context )->spi, command[i] );
179 }
180 for( uint16_t i = 0; i < data_length; i++ )
181 {
182 SpiInOut( &( ( lr1110_t* ) context )->spi, data[i] );
183 }
184 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 1 );
185
186 // 0x011B - LR1110_SYSTEM_SET_SLEEP_OC
187 if( ( ( command[0] << 8 ) | command[1] ) != 0x011B )
188 {
189 return lr1110_hal_wait_on_busy( context );
190 }
191 else
192 {
193 return LR1110_HAL_STATUS_OK;
194 }
195 }
196 return LR1110_HAL_STATUS_ERROR;
197 }
198
lr1110_hal_read(const void * context,const uint8_t * command,const uint16_t command_length,uint8_t * data,const uint16_t data_length)199 lr1110_hal_status_t lr1110_hal_read( const void* context, const uint8_t* command, const uint16_t command_length,
200 uint8_t* data, const uint16_t data_length )
201 {
202 if( lr1110_hal_wakeup( context ) == LR1110_HAL_STATUS_OK )
203 {
204 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 0 );
205
206 for( uint16_t i = 0; i < command_length; i++ )
207 {
208 SpiInOut( &( ( lr1110_t* ) context )->spi, command[i] );
209 }
210
211 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 1 );
212
213 lr1110_hal_wait_on_busy( context );
214
215 // Send dummy byte
216 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 0 );
217
218 SpiInOut( &( ( lr1110_t* ) context )->spi, 0 );
219
220 for( uint16_t i = 0; i < data_length; i++ )
221 {
222 data[i] = SpiInOut( &( ( lr1110_t* ) context )->spi, 0 );
223 }
224
225 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 1 );
226
227 return lr1110_hal_wait_on_busy( context );
228 }
229 return LR1110_HAL_STATUS_ERROR;
230 }
231
lr1110_hal_write_read(const void * context,const uint8_t * command,uint8_t * data,const uint16_t data_length)232 lr1110_hal_status_t lr1110_hal_write_read( const void* context, const uint8_t* command, uint8_t* data,
233 const uint16_t data_length )
234 {
235 if( lr1110_hal_wakeup( context ) == LR1110_HAL_STATUS_OK )
236 {
237 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 0 );
238
239 for( uint16_t i = 0; i < data_length; i++ )
240 {
241 data[i] = SpiInOut( &( ( lr1110_t* ) context )->spi, command[i] );
242 }
243
244 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 1 );
245
246 // 0x011B - LR1110_SYSTEM_SET_SLEEP_OC
247 if( ( ( command[0] << 8 ) | command[1] ) != 0x011B )
248 {
249 return lr1110_hal_wait_on_busy( context );
250 }
251 else
252 {
253 return LR1110_HAL_STATUS_OK;
254 }
255 }
256 return LR1110_HAL_STATUS_ERROR;
257 }
258
lr1110_hal_reset(const void * context)259 void lr1110_hal_reset( const void* context )
260 {
261 GpioWrite( &( ( lr1110_t* ) context )->reset, 0 );
262 DelayMs( 1 );
263 GpioWrite( &( ( lr1110_t* ) context )->reset, 1 );
264 }
265
lr1110_hal_wakeup(const void * context)266 lr1110_hal_status_t lr1110_hal_wakeup( const void* context )
267 {
268 if( ( lr1110_hal_get_operating_mode( context ) == LR1110_HAL_OP_MODE_SLEEP ) ||
269 ( lr1110_hal_get_operating_mode( context ) == LR1110_HAL_OP_MODE_RX_DC ) )
270 {
271 // Wakeup radio
272 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 0 );
273 GpioWrite( &( ( lr1110_t* ) context )->spi.Nss, 1 );
274
275 // Radio is awake in STDBY_RC mode
276 ( ( lr1110_t* ) context )->op_mode = LR1110_HAL_OP_MODE_STDBY_RC;
277 }
278
279 // Wait on busy pin for 100 ms
280 return lr1110_hal_wait_on_busy( context );
281 }
282
lr1110_hal_wait_on_busy(const void * context)283 static lr1110_hal_status_t lr1110_hal_wait_on_busy( const void* context )
284 {
285 while( GpioRead( &( ( lr1110_t* ) context )->busy ) == 1 )
286 {
287 ;
288 }
289 return LR1110_HAL_STATUS_OK;
290 }
291
lr1110_hal_get_operating_mode(const void * context)292 lr1110_hal_operating_mode_t lr1110_hal_get_operating_mode( const void* context )
293 {
294 return ( ( lr1110_t* ) context )->op_mode;
295 }
296
lr1110_hal_set_operating_mode(const void * context,lr1110_hal_operating_mode_t op_mode)297 void lr1110_hal_set_operating_mode( const void* context, lr1110_hal_operating_mode_t op_mode )
298 {
299 ( ( lr1110_t* ) context )->op_mode = op_mode;
300
301 #if defined( USE_RADIO_DEBUG )
302 switch( op_mode )
303 {
304 case LR1110_HAL_OP_MODE_TX:
305 GpioWrite( &DbgPinTx, 1 );
306 GpioWrite( &DbgPinRx, 0 );
307 break;
308 case LR1110_HAL_OP_MODE_RX:
309 case LR1110_HAL_OP_MODE_RX_C:
310 case LR1110_HAL_OP_MODE_RX_DC:
311 GpioWrite( &DbgPinTx, 0 );
312 GpioWrite( &DbgPinRx, 1 );
313 break;
314 default:
315 GpioWrite( &DbgPinTx, 0 );
316 GpioWrite( &DbgPinRx, 0 );
317 break;
318 }
319 #endif
320 }
321