-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathUNO-R4.ino
140 lines (122 loc) · 4.85 KB
/
UNO-R4.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// Copyright (c) 2024 - 2025 Upside Down Labs - contact@upsidedownlabs.tech
// Author: Deepak Khatri
//
// At Upside Down Labs, we create open-source DIY neuroscience hardware and software.
// Our mission is to make neuroscience affordable and accessible for everyone.
// By supporting us with your purchase, you help spread innovation and open science.
// Thank you for being part of this journey with us!
#include "FspTimer.h"
#include <Arduino.h>
// Definitions
#define NUM_CHANNELS 6 // Number of channels supported
#define HEADER_LEN 3 // Header = SYNC_BYTE_1 + SYNC_BYTE_2 + Counter
#define PACKET_LEN (NUM_CHANNELS * 2 + HEADER_LEN + 1) // Packet length = Header + Data + END_BYTE
#define SAMP_RATE 500.0 // Sampling rate (250/500 for UNO R4)
#define SYNC_BYTE_1 0xC7 // Packet first byte
#define SYNC_BYTE_2 0x7C // Packet second byte
#define END_BYTE 0x01 // Packet last byte
#define BAUD_RATE 230400 // Serial connection baud rate
// Global constants and variables
uint8_t packetBuffer[PACKET_LEN]; // The transmission packet
uint8_t currentChannel; // Current channel being sampled
uint16_t adcValue = 0; // ADC current value
bool timerStatus = false; // Timer status bit
bool bufferReady = false; // Buffer ready status bit
FspTimer ChordsTimer;
bool timerStart() {
timerStatus = true;
digitalWrite(LED_BUILTIN, HIGH);
return ChordsTimer.start();
}
bool timerStop() {
timerStatus = false;
bufferReady = false;
digitalWrite(LED_BUILTIN, LOW);
return ChordsTimer.stop();
}
void timerCallback(timer_callback_args_t __attribute((unused)) * p_args) {
if (!timerStatus or Serial.available()) {
timerStop();
return;
}
// Read 6ch ADC inputs and store current values in packetBuffer
for (currentChannel = 0; currentChannel < NUM_CHANNELS; currentChannel++) {
adcValue = analogRead(currentChannel); // Read Analog input
packetBuffer[((2 * currentChannel) + HEADER_LEN)] = highByte(adcValue); // Write High Byte
packetBuffer[((2 * currentChannel) + HEADER_LEN + 1)] = lowByte(adcValue); // Write Low Byte
}
// Increment the packet counter
packetBuffer[2]++;
// Set bufferReady status bit to true
bufferReady = true;
}
bool timerBegin(float sampling_rate) {
uint8_t timer_type = GPT_TIMER;
int8_t timer_channel = FspTimer::get_available_timer(timer_type);
if (timer_channel != -1) {
ChordsTimer.begin(TIMER_MODE_PERIODIC, timer_type, timer_channel, sampling_rate, 0.0f, timerCallback);
ChordsTimer.setup_overflow_irq();
ChordsTimer.open();
return true;
} else {
return false;
}
}
void setup() {
Serial.begin(BAUD_RATE);
while (!Serial) {
; // Wait for serial port to connect. Needed for native USB
}
// Status LED
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// Initialize packetBuffer
packetBuffer[0] = SYNC_BYTE_1; // Sync 0
packetBuffer[1] = SYNC_BYTE_2; // Sync 1
packetBuffer[2] = 0; // Packet counter
packetBuffer[PACKET_LEN - 1] = END_BYTE; // End Byte
// Setup timer
timerBegin(SAMP_RATE);
// Set ADC resolution to 14bit
analogReadResolution(14);
}
void loop() {
// Send data if the buffer is ready and the timer is activ
if (timerStatus and bufferReady) {
Serial.write(packetBuffer, PACKET_LEN);
bufferReady = false;
}
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim(); // Remove extra spaces or newline characters
command.toUpperCase(); // Normalize to uppercase for case-insensitivity
if (command == "WHORU") // Who are you?
{
Serial.println("UNO-R4");
} else if (command == "START") // Start data acquisition
{
timerStart();
} else if (command == "STOP") // Stop data acquisition
{
timerStop();
} else if (command == "STATUS") // Get status
{
Serial.println(timerStatus ? "RUNNING" : "STOPPED");
} else {
Serial.println("UNKNOWN COMMAND");
}
}
}