#include <SPI.h>
// Pin Definitions (Adjust if your wiring differs)
const int MAX7301_CS_PIN = 10; // GPIO 10 for CS
// MAX7301 Register Addresses (from Datasheet Table 3 & others) [cite: 117]
const uint8_t MAX7301_ADDR_NOOP = 0x00;
const uint8_t MAX7301_ADDR_CONFIG = 0x04;
const uint8_t MAX7301_ADDR_TRANSITION_MASK = 0x06;
const uint8_t MAX7301_ADDR_CFG_P7_P4 = 0x09; // Ports P7, P6, P5, P4
const uint8_t MAX7301_ADDR_CFG_P11_P8 = 0x0A;
const uint8_t MAX7301_ADDR_CFG_P15_P12 = 0x0B;
const uint8_t MAX7301_ADDR_CFG_P19_P16 = 0x0C;
const uint8_t MAX7301_ADDR_CFG_P23_P20 = 0x0D;
const uint8_t MAX7301_ADDR_CFG_P27_P24 = 0x0E;
const uint8_t MAX7301_ADDR_CFG_P31_P28 = 0x0F;
// Single Port Registers (Example)
const uint8_t MAX7301_ADDR_PORT4 = 0x24; // P4 register (use for R/W)
const uint8_t MAX7301_ADDR_PORT5 = 0x25; // P5 register (use for R/W)
// Group Port Registers (Example)
const uint8_t MAX7301_ADDR_PORTS_4_11 = 0x44; // Ports P4-P11 (8 ports)
// MAX7301 Configuration bits (Table 2, Table 6) [cite: 52, 130]
const uint8_t MAX7301_CONF_SHUTDOWN_BIT = 0; // S bit (D0), 0=Shutdown, 1=Normal
const uint8_t MAX7301_CONF_TRANSITION_BIT = 7; // M bit (D7), 0=Disabled, 1=Enabled
// SPI Settings
// MAX7301 uses SPI Mode 0 (CPOL=0, CPHA=0). Clock up to 26MHz. [cite: 55, 105]
SPISettings max7301_spi_settings(4000000, MSBFIRST, SPI_MODE0); // 4 MHz clock, MSB first, Mode 0
// --- Low-level SPI Transfer Function ---
uint16_t max7301_transfer(uint16_t command) {
uint16_t received_data = 0;
digitalWrite(MAX7301_CS_PIN, LOW); // Assert CS
SPI.beginTransaction(max7301_spi_settings);
received_data = SPI.transfer16(command); // Send 16-bit command, receive 16 bits
SPI.endTransaction();
digitalWrite(MAX7301_CS_PIN, HIGH); // De-assert CS
// Small delay after CS high can sometimes help in simulation or with real hardware
delayMicroseconds(1);
return received_data;
}
// --- Write Register Function ---
void max7301_write_reg(uint8_t addr, uint8_t data) {
// Format: D15=0 (Write), D14-D8=Addr, D7-D0=Data
uint16_t command = ((uint16_t)addr << 8) | data;
command &= 0x7FFF; // Ensure D15 is 0
max7301_transfer(command);
// Send a No-Op immediately after to allow the custom chip time
// This isn't strictly necessary for real hardware usually, but helps
// ensure the emulator processes the write before we potentially read.
max7301_transfer(0x0000);
}
// --- Read Register Function ---
uint8_t max7301_read_reg(uint8_t addr) {
// Format: D15=1 (Read), D14-D8=Addr, D7-D0=Don't Care (0x00)
uint16_t command = ((uint16_t)addr << 8);
command |= 0x8000; // Set D15 to 1
// First transfer sends the read command. The received data during
// this transfer is from the *previous* transaction (or garbage initially).
max7301_transfer(command);
// Second transfer (e.g., No-Op) clocks out the actual data requested
// by the read command sent in the first transfer.
uint16_t received_data = max7301_transfer(0x0000); // Send No-Op (0x00)
// The requested data is in the lower 8 bits of the received data
return (uint8_t)(received_data & 0xFF);
}
void setup() {
Serial.begin(115200);
while (!Serial); // Wait for Serial Console (helpful in Wokwi)
Serial.println("\nESP32-S3 MAX7301 Wokwi Test");
// --- Configure CS Pin ---
pinMode(MAX7301_CS_PIN, OUTPUT);
digitalWrite(MAX7301_CS_PIN, HIGH); // Ensure CS is high initially
// --- Initialize SPI ---
// Uses default ESP32-S3 SPI pins: SCK=36, MISO=37, MOSI=35
SPI.begin(); // Use default pins
// Alternatively specify pins: SPI.begin(36, 37, 35, MAX7301_CS_PIN); - CS handled manually
Serial.println("SPI Initialized.");
// --- Configure MAX7301 ---
Serial.println("Configuring MAX7301...");
// 1. Take MAX7301 out of shutdown mode
// Read current config, set Shutdown bit (D0) to 1, write back
// uint8_t current_config = max7301_read_reg(MAX7301_ADDR_CONFIG); // Initial read might get garbage
// Instead, just write the desired state directly assuming power-on defaults
uint8_t new_config = 0;
bitSet(new_config, MAX7301_CONF_SHUTDOWN_BIT); // Set S bit to 1 (Normal Operation)
// bitClear(new_config, MAX7301_CONF_TRANSITION_BIT); // Ensure M bit is 0 (Transition Detect Off) - default is 0
max7301_write_reg(MAX7301_ADDR_CONFIG, new_config);
Serial.println(" -> Sent command to exit shutdown.");
// Verify config (optional)
uint8_t read_config = max7301_read_reg(MAX7301_ADDR_CONFIG);
Serial.print(" -> Read Config Register: 0x"); Serial.println(read_config, HEX);
if (bitRead(read_config, MAX7301_CONF_SHUTDOWN_BIT) == 1) {
Serial.println(" -> MAX7301 is Awake!");
} else {
Serial.println(" -> ERROR: MAX7301 failed to wake up!");
while(1); // Halt on error
}
// 2. Configure Port P4 as Output and P5 as Input
// These are controlled by Register 0x09 (P7, P6, P5, P4)
// We want: P7=Input(10), P6=Input(10), P5=Input(10), P4=Output(01)
// Bit pairs: [P7(10) P6(10) P5(10) P4(01)] = 0b 10 10 10 01 = 0xA9
max7301_write_reg(MAX7301_ADDR_CFG_P7_P4, 0xA9);
Serial.println(" -> Configured P4=Output, P5=Input (via Reg 0x09)");
// Verify configuration (optional)
uint8_t p7_p4_config = max7301_read_reg(MAX7301_ADDR_CFG_P7_P4);
Serial.print(" -> Read P7-P4 Config Register (0x09): 0x"); Serial.println(p7_p4_config, HEX);
// 3. Set initial state of P4 (Output) to LOW
max7301_write_reg(MAX7301_ADDR_PORT4, 0x00); // Write 0 to P4 data register
Serial.println(" -> Set initial output P4 LOW.");
Serial.println("MAX7301 Configuration Complete.");
}
bool p4_state = false; // Variable to track the state we want for P4
void loop() {
// --- Toggle Output Port P4 ---
p4_state = !p4_state; // Flip the desired state
max7301_write_reg(MAX7301_ADDR_PORT4, p4_state ? 0x01 : 0x00);
Serial.print("Set P4 Output to: "); Serial.println(p4_state ? "HIGH" : "LOW");
// --- Read Input Port P5 ---
uint8_t p5_value = max7301_read_reg(MAX7301_ADDR_PORT5);
// The read value (0 or 1) is in the LSB (D0)
Serial.print("Read P5 Input value: "); Serial.println(p5_value & 0x01);
// --- Example: Read multiple ports (P4-P11) using group read ---
// uint8_t ports_4_11_values = max7301_read_reg(MAX7301_ADDR_PORTS_4_11);
// Serial.print("Read Ports P4-P11 (Group 0x44): 0b"); Serial.println(ports_4_11_values, BIN);
delay(1000); // Wait a second
}