2727// ///////////////////////////////////////////////////////////////////////////////////////
2828
2929#include " protocentral_afe44xx.h"
30- #include " Protocentral_spo2_algorithm.h"
31- #include " protocentral_hr_algorithm.h"
3230
33- // Default pins CS=7, PWDN=4, DRDY=2
34-
35- #define AFE44XX_CS_PIN 10
36- #define AFE44XX_PWDN_PIN 21
37- #define AFE44XX_DRDY_PIN 14
38-
39- #define CES_CMDIF_PKT_START_1 0x0A
40- #define CES_CMDIF_PKT_START_2 0xFA
41- #define CES_CMDIF_TYPE_DATA 0x02
42- #define CES_CMDIF_PKT_STOP 0x0B
43- #define DATA_LEN 10
31+ // Default pins used by this example
32+ #define AFE44XX_CS_PIN 7
33+ #define AFE44XX_PWDN_PIN 4
34+ #define AFE44XX_DRDY_PIN 2
4435
4536AFE44XX afe44xx (AFE44XX_CS_PIN, AFE44XX_PWDN_PIN, AFE44XX_DRDY_PIN);
4637
47- spo2_algorithm spo2Calc;
48- hr_algo hrCalc;
49-
50- uint16_t irBuffer[100 ];
51- uint16_t redBuffer[100 ];
52- uint8_t bufferIndex = 0 ;
53- uint8_t decimationCounter = 0 ;
54- const uint8_t DECIMATION_FACTOR = 20 ;
55-
56- int32_t heartRate = 0 ;
57- int32_t spo2 = 0 ;
58- int8_t spo2Valid = 0 ;
59- int8_t hrValid = 0 ;
60-
61- uint8_t ppgDataBuff[20 ];
62- uint16_t ppgStreamCnt = 0 ;
63- bool ppgBufReady = false ;
64- bool sensorInitialized = false ;
65-
66- char dataPacket[DATA_LEN];
67- const char dataPacketFooter[2 ] = {0x00 , CES_CMDIF_PKT_STOP};
68- const char dataPacketHeader[5 ] = {CES_CMDIF_PKT_START_1, CES_CMDIF_PKT_START_2, DATA_LEN,
69- ((uint8_t )(DATA_LEN >> 8 )), CES_CMDIF_TYPE_DATA};
70-
7138void setup ()
7239{
73- Serial.begin (57600 );
40+ Serial.begin (115200 );
7441 while (!Serial)
7542 delay (10 );
7643
77- Serial.println (" AFE44XX Raw PPG Data for ProtoCentral OpenView" );
78- Serial.println (" ==============================================" );
44+ Serial.println (" AFE44XX Raw PPG Plot - Example" );
7945
8046 AFE44xxConfig config = AFE44XX::getDefaultConfig ();
81- config.chipType = AFE44xxChipType::AFE4490;
8247 config.led1Current = LEDCurrent::CURRENT_50MA;
8348 config.led2Current = LEDCurrent::CURRENT_50MA;
8449 config.tiaGain = TIAGain::GAIN_500K;
8550 config.sampleRate = SampleRate::RATE_500HZ;
86- config.averagingFactor = 3 ;
8751 config.enableDiagnostics = true ;
8852
8953 Serial.println (" Initializing AFE44XX..." );
9054 AFE44xxError error = afe44xx.begin (config);
91-
9255 if (error != AFE44xxError::NONE)
9356 {
94- Serial.print (" ERROR: Initialization failed - " );
57+ Serial.print (" Initialization failed: " );
9558 Serial.println (afe44xx.getErrorString (error));
96- Serial.println (" Please check connections and reset Arduino" );
97-
9859 while (1 )
99- {
100- delay (5000 );
101- Serial.println (" Check connections: CS=7, PWDN=4, DRDY=2, SPI pins" );
102- }
60+ delay (1000 );
10361 }
10462
63+ // Optional: run self-test
10564 error = afe44xx.performSelfTest ();
10665 if (error != AFE44xxError::NONE)
10766 {
@@ -114,148 +73,29 @@ void setup()
11473 Serial.println (" Self-test passed!" );
11574 }
11675
117- hrCalc.initStatHRM ();
118- sensorInitialized = true ;
119-
120- Serial.println (" Ready! Open ProtoCentral OpenView and connect to this COM port" );
121- Serial.println (" Select 'AFE4490 Raw PPG' mode in OpenView" );
122-
123- delay (2000 );
76+ Serial.println (" Streaming raw PPG data (IR,RED) as CSV" );
77+ Serial.println (" IR,RED" );
12478}
12579
12680void loop ()
12781{
128- if (!sensorInitialized)
129- {
130- delay (1000 );
131- return ;
132- }
133-
13482 AFE44xxData data;
13583 AFE44xxError error = afe44xx.readData (data);
136-
13784 if (error != AFE44xxError::NONE)
13885 {
139- initializeErrorPacket ();
140- sendDataSerialPort ();
141- delay (100 );
142- return ;
143- }
144-
145- if (!data.dataValid )
146- {
147- delay (8 );
86+ Serial.print (" Read error: " );
87+ Serial.println (afe44xx.getErrorString (error));
88+ delay (50 );
14889 return ;
14990 }
15091
151- processSpO2Calculation (data);
152-
153- prepareDataPacket (data);
154-
155- sendDataSerialPort ();
156-
157- static unsigned long lastDiagTime = 0 ;
158- if (millis () - lastDiagTime > 10000 )
159- {
160- checkSensorDiagnostics ();
161- lastDiagTime = millis ();
162- }
163-
164- delay (8 );
165- }
166-
167- void processSpO2Calculation (const AFE44xxData &data)
168- {
169- decimationCounter++;
170- if (decimationCounter >= DECIMATION_FACTOR)
171- {
172- irBuffer[bufferIndex] = (uint16_t )(data.irData >> 4 );
173- redBuffer[bufferIndex] = (uint16_t )(data.redData >> 4 );
174- bufferIndex = (bufferIndex + 1 ) % 100 ;
175- decimationCounter = 0 ;
176-
177- static uint8_t sampleCount = 0 ;
178- sampleCount++;
179- if (sampleCount >= 100 ) {
180- spo2Calc.estimate_spo2 (irBuffer, 100 , redBuffer, &spo2, &spo2Valid, &heartRate, &hrValid);
181- sampleCount = 0 ;
182- }
183- }
184-
185- hrCalc.statHRMAlgo (data.redData );
186- if (hrCalc.HeartRate > 0 )
187- {
188- heartRate = hrCalc.HeartRate ;
189- hrValid = 1 ;
190- }
191- }
192-
193- void prepareDataPacket (const AFE44xxData &data)
194- {
195- memcpy (&dataPacket[0 ], &data.irData , sizeof (int32_t ));
196- memcpy (&dataPacket[4 ], &data.redData , sizeof (int32_t ));
197-
198- if (spo2Valid && spo2 > 0 )
92+ if (data.dataValid )
19993 {
200- dataPacket[8 ] = (uint8_t )constrain (spo2, 0 , 100 );
94+ // Output CSV for plotters or post-processing tools
95+ Serial.print (data.irData );
96+ Serial.print (" ," );
97+ Serial.println (data.redData );
20198 }
202- else
203- {
204- dataPacket[8 ] = 0 ;
205- }
206-
207- if (hrValid && heartRate > 0 )
208- {
209- dataPacket[9 ] = (uint8_t )constrain (heartRate, 0 , 255 );
210- }
211- else
212- {
213- dataPacket[9 ] = 0 ;
214- }
215- }
216-
217- void initializeErrorPacket ()
218- {
219- memset (dataPacket, 0 , DATA_LEN);
220- }
22199
222- void sendDataSerialPort ()
223- {
224- uint8_t fullPacket[5 + DATA_LEN + 2 ];
225- uint8_t idx = 0 ;
226-
227- memcpy (&fullPacket[idx], dataPacketHeader, 5 );
228- idx += 5 ;
229- memcpy (&fullPacket[idx], dataPacket, DATA_LEN);
230- idx += DATA_LEN;
231- memcpy (&fullPacket[idx], dataPacketFooter, 2 );
232-
233- Serial.write (fullPacket, sizeof (fullPacket));
100+ delay (10 );
234101}
235-
236- void checkSensorDiagnostics ()
237- {
238- AFE44xxDiagnostics diag;
239- AFE44xxError error = afe44xx.getDiagnostics (diag);
240-
241- if (error != AFE44xxError::NONE)
242- {
243- return ;
244- }
245-
246- if (diag.ledFault || diag.pdShort || diag.pdOpen || diag.gainError )
247- {
248- afe44xx.clearFaults ();
249- }
250-
251- if (diag.ambientLight > 2000 )
252- {
253- afe44xx.setLEDCurrent (1 , LEDCurrent::CURRENT_75MA);
254- afe44xx.setLEDCurrent (2 , LEDCurrent::CURRENT_75MA);
255- }
256- else if (diag.ambientLight < 100 )
257- {
258- afe44xx.setLEDCurrent (1 , LEDCurrent::CURRENT_25MA);
259- afe44xx.setLEDCurrent (2 , LEDCurrent::CURRENT_25MA);
260- }
261- }
0 commit comments