LCDDriver_NXP_Arduino 0.8.1
Analog Front-End (AFE) device operation sample code for Arduino
Loading...
Searching...
No Matches
AFE_NXP.cpp
Go to the documentation of this file.
1
8
9#include "AFE_NXP.h"
10#include <math.h>
11
12double AFE_base::delay_accuracy = 1.1;
13
14/* AFE_base class ******************************************/
15
16AFE_base::AFE_base( bool spi_addr, bool hsv, int nINT, int DRDY, int SYN, int nRESET ) :
17 dev_add( spi_addr ), highspeed_variant( hsv ), pin_nINT( nINT ), pin_DRDY( DRDY ), pin_SYN( SYN ), pin_nRESET( nRESET ), enabled_channels( 0 )
18{
19 pinMode( pin_nINT, INPUT );
20 pinMode( pin_DRDY, INPUT );
21 pinMode( pin_SYN, OUTPUT );
22 pinMode( pin_nRESET, OUTPUT );
23
24 digitalWrite( pin_SYN, 1 );
25 digitalWrite( pin_nRESET, 1 );
26
27 Serial.print("pin_nRESET = ");
28 Serial.println( pin_nRESET);
29}
30
34
35void AFE_base::init( void )
36{
37#if 0
38 pin_DRDY.rise( DRDY_cb );
39
40 drdy_flag = false;
41 set_DRDY_callback( [this](void){ default_drdy_cb(); } );
42#endif
43}
44
45void AFE_base::begin( void )
46{
47 reset();
48 boot();
49 init();
50}
51
52int32_t AFE_base::start_and_read( int ch )
53{
54// double wait_time = cbf_DRDY ? -1.0 : ch_delay[ ch ] * delay_accuracy;
55 double wait_time = ch_delay[ ch ] * delay_accuracy;
56
57 start( ch );
58 wait_conversion_complete( wait_time );
59
60 return read( ch );
61};
62
63#ifdef NON_TEMPLATE_VERSION_FOR_START_AND_READ
64void AFE_base::start_and_read( raw_t* data )
65{
66 double wait_time = cbf_DRDY ? -1.0 : total_delay * delay_accuracy;
67
68 start();
69 wait_conversion_complete( wait_time );
70
71 read( data );
72};
73template void AFE_base::start_and_read( raw_t* data );
74#endif
75
76int AFE_base::bit_count( uint32_t value )
77{
78 constexpr int bit_length = 32;
79 int count = 0;
80
81 for ( int i = 0; i < bit_length; i++ ) {
82 if ( value & (0x1 << i) )
83 count++;
84 }
85
86 return count;
87}
88
90{
91 if ( 0 < wait )
92 {
93 delay( wait * delay_accuracy * 1000 );
94 return 0;
95 }
96
97 auto timeout_count = timeout_limit;
98
99 while ( !drdy_flag && --timeout_count )
100 ;
101
102 drdy_flag = false;
103
104 if ( !timeout_count )
105 {
106 printf( "DRDY signal wait timeout\r\n" );
107 return -1;
108 }
109 return 0;
110}
111
112/* NAFE13388_Base class ******************************************/
113
114NAFE13388_Base::NAFE13388_Base( bool spi_addr, bool hsv, int nINT, int DRDY, int SYN, int nRESET )
115 : AFE_base( spi_addr, hsv, nINT, DRDY, SYN, nRESET )
116{
117}
118
122
124{
125 command( CMD_ABORT );
126 delay( 1 );
127
128 reg( Register16::SYS_CONFIG0, 0x0010 );
129 delay( 1 );
130}
131
132void NAFE13388_Base::reset( bool hardware_reset )
133{
134 if ( hardware_reset )
135 {
136 digitalWrite( pin_nRESET, 0 );
137 delay( 1 );
138 digitalWrite( pin_nRESET, 1 );
139 }
140 else
141 {
142 command( CMD_RESET );
143 }
144
145 constexpr uint16_t CHIP_READY = 1 << 13;
146 constexpr auto RETRY = 10;
147
148 for ( auto i = 0; i < RETRY; i++ )
149 {
150 delay( 3 );
151 if ( reg( Register16::SYS_STATUS0 ) & CHIP_READY )
152 return;
153 }
154
155 Serial.println( "NAFE13388 couldn't get ready. Check power supply or pin conections\r\n" );
156
157 while ( true )
158 ;
159}
160
161void NAFE13388_Base::open_logical_channel( int ch, const uint16_t (&cc)[ 4 ] )
162{
163 command( ch );
164
165 for ( auto i = 0; i < 4; i++ )
166 reg( Register16::CH_CONFIG0 + i, cc[ i ] );
167
168 const uint16_t setbit = 0x1 << ch;
169 const uint16_t bits = bit_op( Register16::CH_CONFIG4, ~setbit, setbit );
170
171 if ( cc[ 0 ] & 0x0010 )
172 coeff_uV[ ch ] = ((10.0 / (double)(1L << 24)) / pga_gain[ (cc[ 0 ] >> 5) & 0x7 ]) * 1e6;
173 else
174 coeff_uV[ ch ] = (4.0 / (double)(1L << 24)) * 1e6;
175
176 ch_delay[ ch ] = calc_delay( ch );
177 channel_info_update( bits );
178}
179
181{
182 constexpr auto bit_length = 16;
184 total_delay = 0.00;
185
186 for ( auto i = 0; i < bit_length; i++ )
187 {
188 if ( value & (0x1 << i) )
189 {
191 total_delay += ch_delay[ i ];
192 }
193 }
194}
195
197{
198 constexpr static double data_rates[] = { 288000, 192000, 144000, 96000, 72000, 48000, 36000, 24000,
199 18000, 12000, 9000, 6000, 4500, 3000, 2250, 1125,
200 562.5, 400, 300, 200, 100, 60, 50, 30,
201 25, 20, 15, 10, 7.5, };
202 constexpr static uint16_t delays[] = { 0, 2, 4, 6, 8, 10, 12, 14,
203 16, 18, 20, 28, 38, 40, 42, 56,
204 64, 76, 90, 128, 154, 178, 204, 224,
205 256, 358, 512, 716,
206 1024, 1664, 3276, 7680, 19200, 23040, };
207
208 command( ch );
209
210 uint16_t ch_config1 = reg( Register16::CH_CONFIG1 );
211 uint16_t ch_config2 = reg( Register16::CH_CONFIG2 );
212
213 uint8_t adc_data_rate = (ch_config1 >> 3) & 0x001F;
214 uint8_t adc_sinc = (ch_config1 >> 0) & 0x0007;
215 uint8_t ch_delay = (ch_config2 >> 10) & 0x003F;
216 bool adc_normal_setting = (ch_config2 >> 9) & 0x0001;
217 bool ch_chop = (ch_config2 >> 7) & 0x0001;
218
219 double base_freq = data_rates[ adc_data_rate ];
220 double delay_setting = delays[ ch_delay ] / 4608000.00;
221
222 if ( highspeed_variant )
223 {
224 base_freq *= 2.00;
225 delay_setting /= 2.00;
226 }
227
228 if ( (28 < adc_data_rate) || (4 < adc_sinc) || ((adc_data_rate < 12) && (adc_sinc)) )
229 return 0.00;
230
231 if ( !adc_normal_setting )
232 base_freq /= (adc_sinc + 1);
233
234 if ( ch_chop )
235 base_freq /= 2;
236
237#if 0
238 printf( "base_freq = %lf\r\n", base_freq );
239 printf( "delay_setting = %lf\r\n", delay_setting );
240 printf( "total delay = %lf\r\n", (1 / base_freq) + delay_setting );
241#endif
242
243 return (1 / base_freq) + delay_setting;
244}
245
246void NAFE13388_Base::open_logical_channel( int ch, uint16_t cc0, uint16_t cc1, uint16_t cc2, uint16_t cc3 )
247{
248 const ch_setting_t tmp_ch_config = { cc0, cc1, cc2, cc3 };
249 open_logical_channel( ch, tmp_ch_config );
250}
251
253{
254 const uint16_t clearingbit = 0x1 << ch;
255 const uint16_t bits = bit_op( Register16::CH_CONFIG4, ~clearingbit, ~clearingbit );
256
257 channel_info_update( bits );
258}
259
261{
262 reg( Register16::CH_CONFIG4, 0x0000 );
263 channel_info_update( 0x0000 );
264}
265
267{
268 command( ch );
270}
271
273{
275}
276
281
283{
284 bit_op( Register16::SYS_CONFIG0, ~0x0010, flag ? 0x0010 : 0x00 );
285}
286
287int32_t NAFE13388_Base::read( int ch )
288{
289 return reg( Register24::CH_DATA0 + ch );
290}
291
293{
294 burst( (uint32_t *)data, enabled_channels );
295}
296
297void NAFE13388_Base::command( uint16_t com )
298{
299 write_r16( com );
300}
301
302void NAFE13388_Base::reg( Register16 r, uint16_t value )
303{
304 write_r16( static_cast<uint16_t>( r ), value );
305}
306
307void NAFE13388_Base::reg( Register24 r, uint32_t value )
308{
309 write_r24( static_cast<uint16_t>( r ), value );
310}
311
313{
314 return read_r16( static_cast<uint16_t>( r ) );
315}
316
318{
319 return read_r24( static_cast<uint16_t>( r ) );
320}
321
323{
324 return (static_cast<uint32_t>( reg( Register16::PN2 ) ) << 16) | reg( Register16::PN1 );
325}
326
328{
329 return reg( Register16::PN0 ) & 0xF;
330}
331
333{
334 uint64_t serial_number;
335
337 serial_number <<= 24;
339}
340
342{
343 return reg( Register16::DIE_TEMP ) / 64.0;
344}
345
347{
348 constexpr double pga1x_voltage = 5.0;
349 constexpr int adc_resolution = 24;
350 constexpr double pga_gain_setting = 0.2;
351
352 constexpr double fullscale_voltage = pga1x_voltage / pga_gain_setting;
353
354 double fullscale_data = pow( 2, (adc_resolution - 1) );
355 double ref_data_span = ref.high.data - ref.low.data;
356 double ref_voltage_span = ref.high.voltage - ref.low.voltage;
357
358 double dv_slope = ref_data_span / ref_voltage_span;
359 double custom_gain = dv_slope * (fullscale_voltage / fullscale_data);
360 double custom_offset = (dv_slope * ref.low.voltage - ref.low.data) / custom_gain;
361
362 int32_t gain_coeff_cal = reg( Register24::GAIN_COEFF0 + ref.cal_index );
363 int32_t offsset_coeff_cal = reg( Register24::OFFSET_COEFF0 + ref.cal_index );
364 int32_t gain_coeff_new = round( gain_coeff_cal * custom_gain );
365 int32_t offset_coeff_new = round( custom_offset - offsset_coeff_cal );
366
367#if 0
368 printf( "ref_point_high = %8ld @%6.3lf\r\n", ref.high.data, ref.high.voltage );
369 printf( "ref_point_low = %8ld @%6.3lf\r\n", ref.low.data, ref.low.voltage );
370 printf( "gain_coeff_new = %8ld\r\n", gain_coeff_new );
371 printf( "offset_coeff_new = %8ld\r\n", offset_coeff_new );
372#endif
373
374 reg( Register24::GAIN_COEFF0 + ref.coeff_index, gain_coeff_new );
375 reg( Register24::OFFSET_COEFF0 + ref.coeff_index, offset_coeff_new );
376}
377
378int NAFE13388_Base::self_calibrate( int pga_gain_index, int channel_selection, int input_select, double reference_source_voltage, bool use_positive_side )
379{
380 constexpr auto low_gain_index = 2;
381 auto channel_in_use = false;
382 ch_setting_t tmp_ch_config;
383 int gain_index = static_cast<int>( pga_gain_index );
384
385 // logical channel selection to perform the self-calibration
386 // if the chennel in-use, save channel setting to temporal memory
387
388 if ( reg( Register16::CH_CONFIG4 ) & (0x1 << channel_selection) )
389 {
390 channel_in_use = true;
391
392 command( channel_selection );
393
394 for ( auto i = 0; i < 4; i++ )
395 tmp_ch_config[ i ] = reg( Register16::CH_CONFIG0 + i );
396 }
397
398 // if user doesn't specify the channel and voltage, use REFH or REFL
399
400 if ( !input_select )
401 {
402 bool low_gain = (gain_index <= low_gain_index);
403
404 input_select = low_gain ? 0x5 : 0x6;
405 reference_source_voltage = (reg( low_gain ? Register24::OPT_COEF1 : Register24::OPT_COEF2 ) * 5.00) / (double)(1UL << 24);
406
407#if 1
408 printf( "==== self-calibration for PGA gain setting: x%3.1lf\r\n", pga_gain[ gain_index ] );
409 printf( "gain = %s\r\n", low_gain ? "low" : "high" );
410 printf( "REF%s = %10.8lfV\r\n", low_gain ? "H" : "L", reference_source_voltage );
411#endif
412 }
413
414 // logical channel settings
415 // Total 3 settings are prepared to measure reference_voltage, internal-GND and AICOM
416
417 const uint16_t REF_GND = 0x0011 | (gain_index << 5);
418 const uint16_t REF_V = (input_select << (use_positive_side ? 12 : 8)) | REF_GND;
419 const uint16_t REF_COM = 0x7700 | REF_GND;
420 const uint16_t ch_config1 = (gain_index << 12) | 0x00E4;
421 constexpr uint16_t ch_config2 = 0x8480;
422 constexpr uint16_t ch_config3 = 0x0000;
423
424 const ch_setting_t refh = { REF_V, ch_config1, ch_config2, ch_config3 };
425 const ch_setting_t refg = { REF_GND, ch_config1, ch_config2, ch_config3 };
426 const ch_setting_t refc = { REF_COM, ch_config1, ch_config2 & ~0x0080, ch_config3 }; //CH_CHOP:off
427
428 // forcing to set unity-gain and zero-offset
429
430 constexpr raw_t default_gain_coeff_value = 0x1UL << 22;
431 constexpr raw_t default_offset_coeff_value = 0;
432
433 reg( Register24::GAIN_COEFF0 + gain_index, default_gain_coeff_value );
434 reg( Register24::OFFSET_COEFF0 + gain_index, default_offset_coeff_value );
435
436 // measure the logical channel with those different 3 settings
437
438 open_logical_channel( channel_selection, refh );
439 raw_t data_REF = start_and_read( channel_selection );
440
441 open_logical_channel( channel_selection, refg );
442 raw_t data_GND = start_and_read( channel_selection );
443
444 open_logical_channel( channel_selection, refc );
445 raw_t data_COM = start_and_read( channel_selection );
446
447 // calculation
448
449 const double fullscale_voltage = 5.00 / pga_gain[ gain_index ];
450 const double calibrated_gain = (double)(0x1UL << 23) * (reference_source_voltage / fullscale_voltage) / (double)(data_REF - data_GND);
451
452#if 0
453 printf( "data_REF = %8ld (%lfV)\r\n", data_REF, raw2v( channel_selection, data_REF ) );
454 printf( "data_GND = %8ld (%lfmV)\r\n", data_GND, raw2mv( channel_selection, data_GND ) );
455 printf( "data_COM = %8ld (%lfmV)\r\n", data_COM, raw2mv( channel_selection, data_COM ) );
456 printf( "gain adjustment = %8lf (%lfdB)\r\n\r\n", calibrated_gain, 20 * log10( calibrated_gain ) );
457#endif
458
459 if ( !( (0.95 < calibrated_gain) && (calibrated_gain < 1.05) ) )
461
462 const double offset_mv = raw2mv( channel_selection, data_COM );
463
464 if ( !( (-10.0 < offset_mv) && (offset_mv < 10.0) ) )
466
467 // setting registers: GAIN_COEFF[n] and OFFSET_COEFF[n]
468
469 reg( Register24::GAIN_COEFF0 + gain_index, (uint32_t)(default_gain_coeff_value * calibrated_gain) );
470 reg( Register24::OFFSET_COEFF0 + gain_index, default_offset_coeff_value + data_COM );
471
472 // if the channel was in-use, revert the setting
473
474 if ( channel_in_use )
475 open_logical_channel( channel_selection, tmp_ch_config );
476 else
477 close_logical_channel( channel_selection );
478
480}
481
483{
484}
485
486
487/* NAFE13388 class ******************************************/
488
489NAFE13388::NAFE13388( bool spi_addr, bool hsv, int nINT, int DRDY, int SYN, int nRESET )
490 : NAFE13388_Base( spi_addr, hsv, nINT, DRDY, SYN, nRESET )
491{
492}
493
497
498/* NAFE13388_UIM class ******************************************/
499
500NAFE13388_UIM::NAFE13388_UIM( bool spi_addr, bool hsv, int nINT, int DRDY, int SYN, int nRESET )
501 : NAFE13388_Base( spi_addr, hsv, nINT, DRDY, SYN, nRESET )
502{
503}
504
508
510{
511 uint16_t pattern[] = {
512 0x8000, 0x0040, 0x0100, 0x0080, 0x0200, 0x0400, 0x0800, 0x1000,
513 0x2000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0080,
514 0x0100, 0x0040,
515 };
516 reg( Register16::GPIO_CONFIG0, 0xFFC0 );
517 reg( Register16::GPIO_CONFIG1, 0xFFC0 );
518 reg( Register16::GPIO_CONFIG2, 0x0000 );
519
520 for ( auto j = 0; j < 2; j++ )
521 {
522 for ( auto i = 0U; i < sizeof( pattern ) / sizeof( uint16_t ); i++ )
523 {
524 reg( Register16::GPO_DATA, pattern[ i ] );
525 delay( 20 );
526 }
527 }
528
529 uint16_t pv = 0;
530
531 for ( auto j = 0; j < 4; j++ )
532 {
533 for ( auto i = 0; i < 10; i++ )
534 {
535 pv = (j % 2) ? pv & ~pattern[ i ] : pv | pattern[ i ];
536 reg( Register16::GPO_DATA, pv ); delay( 20 );
537 }
538 }
539}
540
541double NAFE13388_Base::pga_gain[] = { 0.2, 0.4, 0.8, 1, 2, 4, 8, 16 };
542
int32_t raw_t
Definition AFE_NXP.h:22
virtual ~AFE_base()
Definition AFE_NXP.cpp:31
int pin_nINT
Definition AFE_NXP.h:205
AFE_base(bool spi_addr, bool highspeed_variant, int nINT, int DRDY, int SYN, int nRESET)
Definition AFE_NXP.cpp:16
virtual void init(void)
Definition AFE_NXP.cpp:35
static constexpr uint32_t timeout_limit
Definition AFE_NXP.h:227
static void DRDY_cb(void)
virtual void begin(void)
Definition AFE_NXP.cpp:45
void default_drdy_cb(void)
double raw2mv(int ch, raw_t value)
Definition AFE_NXP.h:150
bool highspeed_variant
Definition AFE_NXP.h:204
virtual void reset(bool hardware_reset=false)=0
int bit_count(uint32_t value)
Definition AFE_NXP.cpp:76
double coeff_uV[16]
Definition AFE_NXP.h:216
virtual raw_t start_and_read(int ch)
Definition AFE_NXP.cpp:52
int enabled_channels
Definition AFE_NXP.h:213
virtual void start(void)=0
int wait_conversion_complete(double delay=-1.0)
Definition AFE_NXP.cpp:89
volatile bool drdy_flag
Definition AFE_NXP.h:225
int pin_SYN
Definition AFE_NXP.h:207
static double delay_accuracy
Definition AFE_NXP.h:221
double ch_delay[16]
Definition AFE_NXP.h:219
virtual void boot(void)=0
int pin_nRESET
Definition AFE_NXP.h:208
bool dev_add
Definition AFE_NXP.h:203
virtual raw_t read(int ch)=0
double raw2v(int ch, raw_t value)
Definition AFE_NXP.h:160
int pin_DRDY
Definition AFE_NXP.h:206
double total_delay
Definition AFE_NXP.h:220
virtual void start_continuous_conversion()
Definition AFE_NXP.cpp:277
NAFE13388_Base(bool spi_addr, bool highspeed_variant, int nINT, int DRDY, int SYN, int nRESET)
Definition AFE_NXP.cpp:114
virtual void boot(void)
Definition AFE_NXP.cpp:123
void gain_offset_coeff(const ref_points &ref)
Definition AFE_NXP.cpp:346
double calc_delay(int ch)
Definition AFE_NXP.cpp:196
virtual void command(uint16_t com)
Definition AFE_NXP.cpp:297
void blink_leds(void)
Definition AFE_NXP.cpp:482
virtual raw_t read(int ch)
Definition AFE_NXP.cpp:287
static double pga_gain[]
Definition AFE_NXP.h:541
uint32_t bit_op(T rg, uint32_t mask, uint32_t value)
Definition AFE_NXP.h:540
int self_calibrate(int pga_gain_index, int channel_selection=15, int input_select=0, double reference_source_voltage=0, bool use_positive_side=true)
Definition AFE_NXP.cpp:378
struct NAFE13388_Base::_ref_points ref_points
virtual void start(void)
Definition AFE_NXP.cpp:272
virtual void reg(Register16 r, uint16_t value)
Definition AFE_NXP.cpp:302
uint8_t revision_number(void)
Definition AFE_NXP.cpp:327
virtual void close_logical_channel(void)
Definition AFE_NXP.cpp:260
virtual void DRDY_by_sequencer_done(bool flag=true)
Definition AFE_NXP.cpp:282
uint64_t serial_number(void)
Definition AFE_NXP.cpp:332
void channel_info_update(uint16_t value)
Definition AFE_NXP.cpp:180
virtual ~NAFE13388_Base()
Definition AFE_NXP.cpp:119
virtual void reset(bool hardware_reset=false)
Definition AFE_NXP.cpp:132
uint32_t part_number(void)
Definition AFE_NXP.cpp:322
virtual void open_logical_channel(int ch, uint16_t cc0, uint16_t cc1, uint16_t cc2, uint16_t cc3)
Definition AFE_NXP.cpp:246
uint16_t[4] ch_setting_t
Definition AFE_NXP.h:239
float temperature(void)
Definition AFE_NXP.cpp:341
NAFE13388_UIM(bool spi_addr=0, bool highspeed_variant=false, int nINT=3, int DRDY=4, int SYN=6, int nRESET=7)
Definition AFE_NXP.cpp:500
void blink_leds(void)
Definition AFE_NXP.cpp:509
virtual ~NAFE13388_UIM()
Definition AFE_NXP.cpp:505
virtual ~NAFE13388()
Definition AFE_NXP.cpp:494
NAFE13388(bool spi_addr=0, bool highspeed_variant=false, int nINT=2, int DRDY=3, int SYN=5, int nRESET=6)
Definition AFE_NXP.cpp:489
int32_t read_r24(uint16_t reg)
void write_r24(uint16_t reg, uint32_t val)
uint16_t read_r16(uint16_t reg)
void burst(uint32_t *data, int length, int width=3)
void write_r16(uint16_t reg)
reference_point high
Definition AFE_NXP.h:248
reference_point low
Definition AFE_NXP.h:249