Hardware-independent library for controlling the CD74HC4067 16-channel analog multiplexer on Raspberry Pi Pico 2.
The CD74HC4067 is a 16-channel analog multiplexer that allows selection of one input from 16 sources using 4 digital control pins (S0-S3). This library provides channel selection, settling time management, and hardware abstraction.
- Hardware Independence: GPIO pins configured by main application
- 16-Channel Selection: Binary encoded channel selection (0-15)
- Settling Time Management: Configurable timing for analog stability
- Input Validation: GPIO pin validation and duplicate detection
- Debug Support: Comprehensive logging and status reporting
- Test Functions: Built-in channel cycling for hardware validation
The CD74HC4067 requires 4 GPIO pins for channel selection:
S0 (LSB) - Bit 0 of channel number
S1 - Bit 1 of channel number
S2 - Bit 2 of channel number
S3 (MSB) - Bit 3 of channel number
Pin Assignment Examples (fully configurable):
// Example 1: Low GPIO pins
cd74hc4067_config_t config1 = {
.s0_pin = 2, // GP2 - S0 (LSB)
.s1_pin = 3, // GP3 - S1
.s2_pin = 4, // GP4 - S2
.s3_pin = 5, // GP5 - S3 (MSB)
.settling_time_us = 10 // 10μs settling time
};
// Example 2: High GPIO pins
cd74hc4067_config_t config2 = {
.s0_pin = 18, // GP18 - S0 (LSB)
.s1_pin = 19, // GP19 - S1
.s2_pin = 20, // GP20 - S2
.s3_pin = 21, // GP21 - S3 (MSB)
.settling_time_us = 15 // Longer settling for slower circuits
};
// Example 3: Mixed assignment
cd74hc4067_config_t config3 = {
.s0_pin = 6, // GP6 - S0 (LSB)
.s1_pin = 9, // GP9 - S1
.s2_pin = 12, // GP12 - S2
.s3_pin = 15, // GP15 - S3 (MSB)
.settling_time_us = 5 // Fast settling for high-speed circuits
};#include "cd74hc4067.h"
CD74HC4067 mux;
// Configure pins (choose any available GPIO pins)
cd74hc4067_config_t config = {
.s0_pin = 16, // GP16 - S0 (LSB) - any pin works
.s1_pin = 17, // GP17 - S1 - any pin works
.s2_pin = 18, // GP18 - S2 - any pin works
.s3_pin = 19, // GP19 - S3 (MSB) - any pin works
.settling_time_us = 10 // 10μs settling time
};
// Initialize multiplexer
if (!mux.init(config)) {
printf("Failed to initialize multiplexer\n");
return;
}
// Select channel 5
if (mux.selectChannel(5)) {
printf("Channel 5 selected\n");
// Read analog value from your ADC here
}#include "cd74hc4067.h"
#include "hardware/adc.h"
CD74HC4067 mux;
void setupSystem() {
// Initialize ADC
adc_init();
adc_gpio_init(28); // GP28 as ADC input
adc_select_input(2); // ADC2 (GP28)
// Initialize multiplexer
cd74hc4067_config_t config = {8, 9, 10, 11, 10};
mux.init(config);
}
uint16_t readChannel(uint8_t channel) {
if (mux.selectChannel(channel)) {
// Mux automatically waits for settling time
return adc_read();
}
return 0;
}void scanAllChannels() {
for (uint8_t ch = 0; ch < 16; ch++) {
if (mux.selectChannel(ch)) {
uint16_t value = adc_read();
printf("Channel %d: %d\n", ch, value);
}
}
}bool init(const cd74hc4067_config_t& config)Initialize multiplexer with GPIO pin configuration.
Parameters:
config: Pin assignments and timing settings
Returns: true if initialization successful
bool selectChannel(uint8_t channel)Select active channel (0-15) with automatic settling time.
Parameters:
channel: Channel number (0-15)
Returns: true if selection successful
uint8_t getCurrentChannel() const
bool isValidChannel(uint8_t channel) const
uint32_t getSettlingTime() const
void setSettlingTime(uint32_t settling_time_us)void printStatus() const // Show current configuration
void testAllChannels(uint32_t delay_ms) // Cycle through all channels
const char* getChannelName(uint8_t channel) // Get channel name for loggingtypedef struct {
uint s0_pin; // S0 select pin (LSB)
uint s1_pin; // S1 select pin
uint s2_pin; // S2 select pin
uint s3_pin; // S3 select pin (MSB)
uint32_t settling_time_us; // Settling time after channel change
} cd74hc4067_config_t;#define CD74HC4067_DEFAULT_SETTLING_TIME_US 10 // Default 10μs settling time
#define CD74HC4067_MAX_CHANNELS 16 // 16 channels (0-15)
#define CD74HC4067_INVALID_CHANNEL 0xFF // Invalid channel markerThe CD74HC4067 library coordinates with pot_scanner for potentiometer reading:
#include "cd74hc4067.h"
#include "pot_scanner.h"
CD74HC4067 mux;
PotScanner scanner;
void setupPotSystem() {
// Initialize multiplexer
cd74hc4067_config_t mux_config = {8, 9, 10, 11, 10};
mux.init(mux_config);
// Initialize pot scanner
pot_scanner_config_t scan_config = {28, 0.15f, 100, 10};
scanner.init(scan_config);
scanner.startScanning();
}
void readPotentiometer(uint8_t pot_channel) {
// Select multiplexer channel
mux.selectChannel(pot_channel);
// Update pot scanner reading
scanner.updateChannel(pot_channel);
// Get filtered value
float value = scanner.getFilteredValue(pot_channel);
printf("Pot %d: %.1f\n", pot_channel, value);
}- Full GPIO Flexibility: Use any 4 available GPIO pins (0-28 on Pico 2)
- No Pin Restrictions: Unlike I2C/SPI, S0-S3 can be assigned to any digital pins
- Pin Validation: Prevents duplicate pin assignments and invalid GPIO numbers
- Settling Time: Default 10μs, adjustable for different hardware characteristics
- Channel Encoding: Binary encoding on S0-S3 pins (automatic)
- Current Draw: Low power CMOS design
- Hardware Independence: Library doesn't impose any pin assignments
The library validates:
- GPIO pin numbers (0-28 range)
- Duplicate pin assignments
- Channel numbers (0-15 range)
- Initialization state before operations
All validation failures are logged with specific error messages.
Uses console_logger with TAG_MUX for multiplexer-specific messages:
LOG_MUX_DEBUG("Selecting channel %d", channel);
LOG_MUX_INFO("CD74HC4067 initialized");
LOG_MUX_ERROR("Invalid channel %d", channel);Add to your project's CMakeLists.txt:
# Add CD74HC4067 library
add_subdirectory($ENV{LIBRARIES_PATH}/cd74hc4067 cd74hc4067)
# Link to your target
target_link_libraries(your_project
cd74hc4067
console_logger
# ... other libraries
)Hardware: Raspberry Pi Pico 2 + CD74HC4067 + 16 potentiometers ADC Filtering: 470Ω + 47nF RC filter on Pico ADC pin GP28
// Tested stable configuration for pot scanning
cd74hc4067_config_t mux_config = {
.s0_pin = 8, // GP8 -> POTS-MUX-S0
.s1_pin = 9, // GP9 -> POTS-MUX-S1
.s2_pin = 10, // GP10 -> POTS-MUX-S2
.s3_pin = 11, // GP11 -> POTS-MUX-S3
.settling_time_us = 500 // 500μs settling time for clean readings
};Notes:
- 500μs settling time eliminates crosstalk between channels
- RC filter (470Ω + 47nF) on ADC pin prevents noise injection
- Next board revision will include RC filters on each pot input for faster scanning
- Current configuration provides snappy response with clean channel isolation
- 1.1.0 (September 29, 2025): Validated hardware settings for pot scanning applications
- 1.0.0: Initial release with 16-channel selection and hardware independence
- Hardware-agnostic GPIO configuration
- Binary channel encoding with settling time management
- Comprehensive validation and logging