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