AFE_NXP_Arduino 2.0.3
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
9#include "AFE_NXP.h"
10#include <math.h>
11
12double AFE_base::delay_accuracy = 1.1;
13
18
23
24template<>
29
30template<>
36
41
46
50
55
57{
58 afe_ptr->open_logical_channel( ch_number, cc );
59}
60
62{
63 const ch_setting_t tmp_ch_config = { cc0, cc1, cc2, cc3 };
64 afe_ptr->open_logical_channel( ch_number, tmp_ch_config );
65}
66
67
68/* AFE_base class ******************************************/
69
83
87
97
98void AFE_base::begin( void )
99{
100 instance = this;
101
102 SPI_for_AFE::init(); // set proper SPI_CS = HIGH state. This is required for UNO R4
103
104 reset();
105 boot();
106 init();
107}
108
109void AFE_base::set_DRDY_callback( callback_fp_t func )
110{
111 cbf_DRDY = func;
112}
113
115{
116 if ( cbf_DRDY )
117 cbf_DRDY();
118}
119
121{
122 if ( nullptr != instance )
124}
125
127{
128 drdy_count++;
129 drdy_flag = true;
130}
131
133{
134 double wait_time = cbf_DRDY ? -1.0 : ch_delay[ ch ] * delay_accuracy;
135
136 start( ch );
138
139 return read( ch );
140};
141
142#ifdef NON_TEMPLATE_VERSION_FOR_START_AND_READ
143void AFE_base::start_and_read( raw_t* data )
144{
145 double wait_time = cbf_DRDY ? -1.0 : total_delay * delay_accuracy;
146
147 start();
149
150 read( data );
151};
152template void AFE_base::start_and_read( raw_t* data );
153#endif
154
155int AFE_base::bit_count( uint32_t value )
156{
157 constexpr int bit_length = 32;
158 int count = 0;
159
160 for ( int i = 0; i < bit_length; i++ ) {
161 if ( value & (0x1 << i) )
162 count++;
163 }
164
165 return count;
166}
167
169{
170 if ( 0 < wait )
171 {
172 if ( wait < 0.016 )
174 else
175 delay( wait * delay_accuracy * 1e3 );
176 return 0;
177 }
178
180
181 while ( !drdy_flag && --timeout_count )
182 ;
183
184 drdy_flag = false;
185
186 if ( !timeout_count )
187 {
188 printf( "DRDY signal wait timeout\r\n" );
189 return -1;
190 }
191 return 0;
192}
193
195{
196 if ( use )
198 else
199 set_DRDY_callback( nullptr );
200}
201
202
205
206/* NAFE13388_Base class ******************************************/
207
208NAFE13388_Base::NAFE13388_Base( bool spi_addr, bool hsv, int nINT, int DRDY, int SYN, int nRESET, int DRDY_input, int SYNCDAC )
209 : AFE_base( spi_addr, hsv, nINT, DRDY, SYN, nRESET, DRDY_input, SYNCDAC )
210{
211 for ( auto i = 0; i < 16; i++ )
212 {
213 logical_channel[ i ].afe_ptr = this;
215 }
216}
217
221
223{
224 command( CMD_ABORT );
225 delay( 1 );
226
228}
229
230void NAFE13388_Base::reset( bool hardware_reset )
231{
232 if ( hardware_reset )
233 {
235 delay( 1 );
237 }
238 else
239 {
240 command( CMD_RESET );
241 }
242
243 constexpr uint16_t CHIP_READY = 1 << 13;
244 constexpr auto RETRY = 10;
245
246 for ( auto i = 0; i < RETRY; i++ )
247 {
248 delay( 3 );
250 return;
251 }
252
253 Serial.println( "NAFE13388 couldn't get ready. Check power supply or pin conections\r\n" );
254
255 while ( true )
256 ;
257}
258
259void NAFE13388_Base::open_logical_channel( int ch, const uint16_t (&cc)[ 4 ] )
260{
261 command( ch );
262
263 if ( cc[ 0 ] & 0x0010 )
264 {
265 coeff_V[ ch ] = ((10.0 / (double)(1L << 24)) / pga_gain[ (cc[ 0 ] >> 5) & 0x7 ]);
266 mux_setting[ ch ] = HV_MUX;
267 }
268 else
269 {
270 coeff_V[ ch ] = ((10.0 / (double)(1L << 24)) / 2.5);
271 mux_setting[ ch ] = (cc[ 0 ] >> 1) & 0x7;
272 }
273
274 for ( auto i = 0; i < 4; i++ )
276
278
279 ch_delay[ ch ] = calc_delay( ch );
280}
281
283{
284 constexpr auto bit_length = 16;
286 total_delay = 0.00;
287
288 memset( sequence_order, 0, 16 );
289
290 for ( auto i = 0; i < bit_length; i++ )
291 {
292 if ( value & (0x1 << i) )
293 {
296 total_delay += ch_delay[ i ];
297 }
298 }
299
300#if 0
301 for ( auto i = 0; i < bit_length; i++ )
302 printf( " %x", sequence_order[ i ] );
303 printf( "\r\n" );
304#endif
305}
306
308{
309 constexpr static double data_rates[] = { 288000, 192000, 144000, 96000, 72000, 48000, 36000, 24000,
310 18000, 12000, 9000, 6000, 4500, 3000, 2250, 1125,
311 562.5, 400, 300, 200, 100, 60, 50, 30,
312 25, 20, 15, 10, 7.5, };
313 constexpr static uint16_t delays[] = { 0, 2, 4, 6, 8, 10, 12, 14,
314 16, 18, 20, 28, 38, 40, 42, 56,
315 64, 76, 90, 128, 154, 178, 204, 224,
316 256, 358, 512, 716,
317 1024, 1664, 3276, 7680, 19200, 23040, };
318
319 command( ch );
320
323
324 uint8_t adc_data_rate = (ch_config1 >> 3) & 0x001F;
325 uint8_t adc_sinc = (ch_config1 >> 0) & 0x0007;
326 uint8_t ch_delay = (ch_config2 >> 10) & 0x003F;
327 bool adc_normal_setting = (ch_config2 >> 9) & 0x0001;
328 bool ch_chop = (ch_config2 >> 7) & 0x0001;
329
331 double delay_setting = delays[ ch_delay ] / 4608000.00;
332
333 if ( highspeed_variant )
334 {
335 base_freq *= 2.00;
336 delay_setting /= 2.00;
337 }
338
339 if ( (28 < adc_data_rate) || (4 < adc_sinc) || ((adc_data_rate < 12) && (adc_sinc)) )
340 return 0.00;
341
342 if ( !adc_normal_setting )
343 base_freq /= (adc_sinc + 1);
344
345 if ( ch_chop )
346 base_freq /= 2;
347
348#if 0
349 printf( "base_freq = %lf\r\n", base_freq );
350 printf( "delay_setting = %lf\r\n", delay_setting );
351 printf( "total delay = %lf\r\n", (1 / base_freq) + delay_setting );
352#endif
353
354 return (1 / base_freq) + delay_setting;
355}
356
357void NAFE13388_Base::open_logical_channel( int ch, uint16_t cc0, uint16_t cc1, uint16_t cc2, uint16_t cc3 )
358{
359 const ch_setting_t tmp_ch_config = { cc0, cc1, cc2, cc3 };
361}
362
370
378
380{
381 reg( Register16::CH_CONFIG4, 0x0000 );
382 channel_info_update( 0x0000 );
383}
384
386{
387 command( ch );
389}
390
392{
394}
395
400
402{
403 bit_op( Register16::SYS_CONFIG0, ~0x0010, flag ? 0x0010 : 0x00 );
404}
405
406int32_t NAFE13388_Base::read( int ch )
407{
408 return reg( Register24::CH_DATA0 + ch );
409}
410
412{
413 burst( (uint32_t *)data, enabled_channels );
414}
415
417{
418 raw_t raw_data[ 16 ];
419
420 read( raw_data );
421
422 for ( auto i = 0; i < enabled_channels; i++ )
423 data[ i ] = raw2v( sequence_order[ i ], raw_data[ i ] );
424}
425
426void NAFE13388_Base::command( uint16_t com )
427{
428 write_r16( com );
429}
430
431void NAFE13388_Base::reg( Register16 r, uint16_t value )
432{
433 write_r16( static_cast<uint16_t>( r ), value );
434}
435
436void NAFE13388_Base::reg( Register24 r, uint32_t value )
437{
438 write_r24( static_cast<uint16_t>( r ), value );
439}
440
442{
443 return read_r16( static_cast<uint16_t>( r ) );
444}
445
447{
448 return read_r24( static_cast<uint16_t>( r ) );
449}
450
452{
453 return (static_cast<uint32_t>( reg( Register16::PN2 ) ) << 16) | reg( Register16::PN1 );
454}
455
457{
458 return reg( Register16::PN0 ) & 0xF;
459}
460
469
471{
472 return ((int16_t)reg( Register16::DIE_TEMP )) / 64.0;
473}
474
476{
477 constexpr double pga1x_voltage = 5.0;
478 constexpr int adc_resolution = 24;
479 constexpr double pga_gain_setting = 0.2;
480
482
483 double fullscale_data = pow( 2, (adc_resolution - 1) );
484 double ref_data_span = ref.high.data - ref.low.data;
485 double ref_voltage_span = ref.high.voltage - ref.low.voltage;
486
489 double custom_offset = (dv_slope * ref.low.voltage - ref.low.data) / custom_gain;
490
495
496#if 0
497 printf( "ref_point_high = %8ld @%6.3lf\r\n", ref.high.data, ref.high.voltage );
498 printf( "ref_point_low = %8ld @%6.3lf\r\n", ref.low.data, ref.low.voltage );
499 printf( "gain_coeff_new = %8ld\r\n", gain_coeff_new );
500 printf( "offset_coeff_new = %8ld\r\n", offset_coeff_new );
501#endif
502
505}
506
507int NAFE13388_Base::self_calibrate( int pga_gain_index, int channel_selection, int input_select, double reference_source_voltage, bool use_positive_side )
508{
509 constexpr auto low_gain_index = 2;
510 auto channel_in_use = false;
512 int gain_index = static_cast<int>( pga_gain_index );
513
514 // logical channel selection to perform the self-calibration
515 // if the chennel in-use, save channel setting to temporal memory
516
517 if ( reg( Register16::CH_CONFIG4 ) & (0x1 << channel_selection) )
518 {
519 channel_in_use = true;
520
522
523 for ( auto i = 0; i < 4; i++ )
525 }
526
527 // if user doesn't specify the channel and voltage, use REFH or REFL
528
529 if ( !input_select )
530 {
532
533 input_select = low_gain ? 0x5 : 0x6;
535
536#if 1
537 printf( "==== self-calibration for PGA gain setting: x%3.1lf\r\n", pga_gain[ gain_index ] );
538 printf( "gain = %s\r\n", low_gain ? "low" : "high" );
539 printf( "REF%s = %10.8lfV\r\n", low_gain ? "H" : "L", reference_source_voltage );
540#endif
541 }
542
543 // logical channel settings
544 // Total 3 settings are prepared to measure reference_voltage, internal-GND and AICOM
545
546 const uint16_t REF_GND = 0x0011 | (gain_index << 5);
547 const uint16_t REF_V = (input_select << (use_positive_side ? 12 : 8)) | REF_GND;
548 const uint16_t REF_COM = 0x7700 | REF_GND;
549 const uint16_t ch_config1 = (gain_index << 12) | 0x00E4;
550 constexpr uint16_t ch_config2 = 0x8480;
551 constexpr uint16_t ch_config3 = 0x0000;
552
555 const ch_setting_t refc = { REF_COM, ch_config1, ch_config2 & ~0x0080, ch_config3 }; //CH_CHOP:off
556
557 // forcing to set unity-gain and zero-offset
558
559 constexpr raw_t default_gain_coeff_value = 0x1UL << 22;
560 constexpr raw_t default_offset_coeff_value = 0;
561
564
565 // measure the logical channel with those different 3 settings
566
569
572
575
576 // calculation
577
578 const double fullscale_voltage = 5.00 / pga_gain[ gain_index ];
579 const double calibrated_gain = (double)(0x1UL << 23) * (reference_source_voltage / fullscale_voltage) / (double)(data_REF - data_GND);
580
581#if 0
582 printf( "data_REF = %8ld (%lfV)\r\n", data_REF, raw2v( channel_selection, data_REF ) );
583 printf( "data_GND = %8ld (%lfmV)\r\n", data_GND, raw2mv( channel_selection, data_GND ) );
584 printf( "data_COM = %8ld (%lfmV)\r\n", data_COM, raw2mv( channel_selection, data_COM ) );
585 printf( "gain adjustment = %8lf (%lfdB)\r\n\r\n", calibrated_gain, 20 * log10( calibrated_gain ) );
586#endif
587
588 if ( !( (0.95 < calibrated_gain) && (calibrated_gain < 1.05) ) )
590
591 const double offset_mv = raw2mv( channel_selection, data_COM );
592
593 if ( !( (-10.0 < offset_mv) && (offset_mv < 10.0) ) )
595
596 // setting registers: GAIN_COEFF[n] and OFFSET_COEFF[n]
597
600
601 // if the channel was in-use, revert the setting
602
603 if ( channel_in_use )
605 else
607
609}
610
612{
613}
614
615
616/* NAFE13388 class ******************************************/
617
618NAFE13388::NAFE13388( bool spi_addr, bool hsv, int nINT, int DRDY, int SYN, int nRESET, int DRDY_input, int SYNCDAC )
619 : NAFE13388_Base( spi_addr, hsv, nINT, DRDY, SYN, nRESET, DRDY_input, SYNCDAC )
620{
621}
622
626
627/* NAFE13388_UIM class ******************************************/
628
629NAFE13388_UIM::NAFE13388_UIM( bool spi_addr, bool hsv, int nINT, int DRDY, int SYN, int nRESET, int DRDY_input, int SYNCDAC )
630 : NAFE13388_Base( spi_addr, hsv, nINT, DRDY, SYN, nRESET, DRDY_input, SYNCDAC )
631{
632}
633
637
639{
640 uint16_t pattern[] = {
641 0x8000, 0x0040, 0x0100, 0x0080, 0x0200, 0x0400, 0x0800, 0x1000,
642 0x2000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0080,
643 0x0100, 0x0040,
644 };
645 reg( Register16::GPIO_CONFIG0, 0xFFC0 );
646 reg( Register16::GPIO_CONFIG1, 0xFFC0 );
647 reg( Register16::GPIO_CONFIG2, 0x0000 );
648
649 for ( auto j = 0; j < 2; j++ )
650 {
651 for ( auto i = 0U; i < sizeof( pattern ) / sizeof( uint16_t ); i++ )
652 {
654 delay( 20 );
655 }
656 }
657
658 uint16_t pv = 0;
659
660 for ( auto j = 0; j < 4; j++ )
661 {
662 for ( auto i = 0; i < 10; i++ )
663 {
664 pv = (j % 2) ? pv & ~pattern[ i ] : pv | pattern[ i ];
665 reg( Register16::GPO_DATA, pv ); delay( 20 );
666 }
667 }
668}
669
670double NAFE13388_Base::pga_gain[] = { 0.2, 0.4, 0.8, 1, 2, 4, 8, 16 };
671
virtual void enable_logical_channel(int ch)=0
static AFE_base * instance
Definition AFE_NXP.h:258
static callback_fp_t cbf_DRDY
Definition AFE_NXP.h:250
int32_t raw_t
Definition AFE_NXP.h:22
double volt_t
Definition AFE_NXP.h:23
void use_DRDY_trigger(bool use=true)
Definition AFE_NXP.cpp:194
virtual ~AFE_base()
Definition AFE_NXP.cpp:84
static void DRDY_cb()
Definition AFE_NXP.cpp:114
virtual double raw2v(int ch, raw_t value)=0
int pin_nINT
Definition AFE_NXP.h:217
virtual void set_DRDY_callback(callback_fp_t fnc)
Definition AFE_NXP.cpp:109
int pin_DRDY_input
Definition AFE_NXP.h:221
virtual void init(void)
Definition AFE_NXP.cpp:88
static constexpr uint32_t timeout_limit
Definition AFE_NXP.h:244
virtual void begin(void)
Definition AFE_NXP.cpp:98
double raw2mv(int ch, raw_t value)
Definition AFE_NXP.h:174
bool highspeed_variant
Definition AFE_NXP.h:216
virtual void reset(bool hardware_reset=false)=0
uint32_t drdy_count
Definition AFE_NXP.h:248
int bit_count(uint32_t value)
Definition AFE_NXP.cpp:155
int pin_SYNCDAC
Definition AFE_NXP.h:222
void default_drdy_cb()
Definition AFE_NXP.cpp:126
void(* callback_fp_t)(void)
Definition AFE_NXP.h:46
double coeff_V[16]
Definition AFE_NXP.h:234
virtual raw_t start_and_read(int ch)
Definition AFE_NXP.cpp:132
int enabled_channels
Definition AFE_NXP.h:228
uint8_t sequence_order[16]
Definition AFE_NXP.h:231
static void static_default_drdy_cb()
Definition AFE_NXP.cpp:120
virtual void start(void)=0
AFE_base(bool spi_addr, bool highspeed_variant, int nINT, int DRDY, int SYN, int nRESET, int DRDY_input, int SYNCDAC)
Definition AFE_NXP.cpp:70
int wait_conversion_complete(double delay=-1.0)
Definition AFE_NXP.cpp:168
virtual void close_logical_channel(int ch)=0
volatile bool drdy_flag
Definition AFE_NXP.h:249
int pin_SYN
Definition AFE_NXP.h:219
static double delay_accuracy
Definition AFE_NXP.h:242
double ch_delay[16]
Definition AFE_NXP.h:240
int mux_setting[16]
Definition AFE_NXP.h:237
virtual void boot(void)=0
int pin_nRESET
Definition AFE_NXP.h:220
bool dev_add
Definition AFE_NXP.h:215
virtual raw_t read(int ch)=0
int pin_DRDY
Definition AFE_NXP.h:218
double total_delay
Definition AFE_NXP.h:241
void enable(void)
Definition AFE_NXP.cpp:14
AFE_base * afe_ptr
Definition AFE_NXP.h:285
void disable(void)
Definition AFE_NXP.cpp:19
void configure(const uint16_t(&cc)[4])
Definition AFE_NXP.cpp:56
virtual void start_continuous_conversion()
Definition AFE_NXP.cpp:396
double raw2v(int ch, raw_t value)
Definition AFE_NXP.h:410
virtual void boot(void)
Definition AFE_NXP.cpp:222
void gain_offset_coeff(const ref_points &ref)
Definition AFE_NXP.cpp:475
double calc_delay(int ch)
Definition AFE_NXP.cpp:307
virtual void command(uint16_t com)
Definition AFE_NXP.cpp:426
void blink_leds(void)
Definition AFE_NXP.cpp:611
virtual raw_t read(int ch)
Definition AFE_NXP.cpp:406
LogicalChannel logical_channel[16]
Definition AFE_NXP.h:344
static double pga_gain[]
Definition AFE_NXP.h:670
uint32_t bit_op(T rg, uint32_t mask, uint32_t value)
Definition AFE_NXP.h:660
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:507
virtual void start(void)
Definition AFE_NXP.cpp:391
virtual void reg(Register16 r, uint16_t value)
Definition AFE_NXP.cpp:431
uint8_t revision_number(void)
Definition AFE_NXP.cpp:456
virtual void close_logical_channel(void)
Definition AFE_NXP.cpp:379
virtual void DRDY_by_sequencer_done(bool flag=true)
Definition AFE_NXP.cpp:401
uint64_t serial_number(void)
Definition AFE_NXP.cpp:461
void channel_info_update(uint16_t value)
Definition AFE_NXP.cpp:282
virtual ~NAFE13388_Base()
Definition AFE_NXP.cpp:218
void enable_logical_channel(int ch)
Definition AFE_NXP.cpp:363
virtual void reset(bool hardware_reset=false)
Definition AFE_NXP.cpp:230
uint32_t part_number(void)
Definition AFE_NXP.cpp:451
virtual void open_logical_channel(int ch, uint16_t cc0, uint16_t cc1, uint16_t cc2, uint16_t cc3)
Definition AFE_NXP.cpp:357
NAFE13388_Base(bool spi_addr, bool highspeed_variant, int nINT, int DRDY, int SYN, int nRESET, int DRDY_input, int SYNCDAC)
Definition AFE_NXP.cpp:208
uint16_t[4] ch_setting_t
Definition AFE_NXP.h:291
float temperature(void)
Definition AFE_NXP.cpp:470
NAFE13388_UIM(bool spi_addr=0, bool highspeed_variant=false, int nINT=3, int DRDY=4, int SYN=6, int nRESET=7, int DRDY_input=2, int SYNCDAC=14)
Definition AFE_NXP.cpp:629
void blink_leds(void)
Definition AFE_NXP.cpp:638
virtual ~NAFE13388_UIM()
Definition AFE_NXP.cpp:634
virtual ~NAFE13388()
Definition AFE_NXP.cpp:623
NAFE13388(bool spi_addr=0, bool highspeed_variant=false, int nINT=2, int DRDY=4, int SYN=5, int nRESET=6, int DRDY_input=15, int SYNCDAC=14)
Definition AFE_NXP.cpp:618
int32_t read_r24(uint16_t reg)
void init(void)
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)