//MCP4151 digital pot (bitbanged control) for Afterburner GAL project. // * compatible with MCP4131 (resolution of the wiper is divided by 2) // * the storage for tap indices is 8bit wide, therefore we must not use index 256. // 2024-02-02 Minor change #ifndef __AFTB_MCP4131_H__ #define __AFTB_MCP4131_H__ //set default pins #ifndef POT_CS #define POT_CS A3 #endif #ifndef POT_CLK #define POT_CLK A4 #endif #ifndef POT_DAT #define POT_DAT A5 #endif #ifndef POT_DEFAULT_VALUE #define POT_DEFAULT_VALUE 0x40 #endif #ifndef POT_WIPER_ENABLED #define POT_WIPER_ENABLED 0 #endif #define ADDR_WIPER 0 #define ADDR_WIPER0 0 #define ADDR_WIPER1 1 #define ADDR_TCON 4 #define ADDR_STAT 5 #define ADDR_INCREMENT 100 #define CMD_READ (0b11 << 10) #define CMD_INCREMENT (0b01 << 2) #define mcp4131_disableWiper() mcp4131_write(ADDR_TCON, 0b111111101) #define mcp4131_enableWiper() mcp4131_write(ADDR_TCON, 0b111111111) #define mcp4131_read(A) mcp4131_reg((A),0,1) #define mcp4131_write(A,V) mcp4131_reg((A),(V),0) static uint8_t mcp4131_detected; // read or write the mcp4131 register static uint16_t mcp4131_reg(uint8_t address, uint16_t value, uint8_t read_reg) { int8_t i = 15; //16 bit command uint16_t r = address; r <<= 12; if (mcp4131_detected && address == ADDR_WIPER) { value >>= 1; //divide the wiper value by 2 value++; // ensure we use the last tap (index 128) } if (address == ADDR_INCREMENT) { r = CMD_INCREMENT; i = 7; // 8 bit command } else if (read_reg) { r |= CMD_READ; } else { r |= value & 0x1FF; // clamp value to 9 bits } //setup Clock and and Data (SPI mode 0,0) digitalWrite(POT_CLK, 0); digitalWrite(POT_DAT, 0); delayMicroseconds(50); //activate IC digitalWrite(POT_CS, 0); while (i >= 0) { //write address and command (bits 15 to 10) if ((!read_reg) || i > 9) { uint16_t mask = (1 << i); digitalWrite(POT_DAT, (r & mask) ? 1 : 0); } digitalWrite(POT_CLK, 1); //rise the clock //only when reading reg if (read_reg) { //switch the DAT pin to Input if (i == 10) { pinMode(POT_DAT, INPUT); } //read bits 9 to 0 if (i < 10) { r |= (digitalRead(POT_DAT) << i); //read after rising edge } } digitalWrite(POT_CLK, 0); //fall the clock i--; } if (read_reg) { pinMode(POT_DAT, OUTPUT); } if (mcp4131_detected && address == ADDR_WIPER && read_reg) { r--; r >>= 1; //multiply the wiper value by 2 } //disable IC digitalWrite(POT_CS, 1); return r & 0x1FF; //clamp value to 9 bits } static void mcp4131_init(void) { pinMode(POT_CS, OUTPUT); pinMode(POT_CLK, OUTPUT); pinMode(POT_DAT, OUTPUT); digitalWrite(POT_CS, 1); //unselect the POT's SPI bus } // initialisation and detection // returns 1 if POT is detected, 0 otherwise static uint8_t mcp4131_detect(void) { uint16_t r; mcp4131_detected = 0; mcp4131_disableWiper(); //note checking is done while the wiper is disabled - no resistance is applied mcp4131_write(ADDR_WIPER, 0b1010); r = mcp4131_read(ADDR_WIPER); if (r != 0b1010) { return 0; } mcp4131_write(ADDR_WIPER, 0b101); r = mcp4131_read(ADDR_WIPER); if (r != 0b101) { return 0; } //sanity check whether the incrementing works mcp4131_write(ADDR_WIPER, 127); mcp4131_write(ADDR_INCREMENT, 0); r = mcp4131_read(ADDR_WIPER); if (r != 128) { return 0; } //detect MCP4151 by incrementing again - MCP4131 clamps the value to 128, MCP4151 increments to 129 mcp4131_write(ADDR_INCREMENT, 0); r = mcp4131_read(ADDR_WIPER); #if 0 Serial.print(F("MCP4151 detect: ")); Serial.println(r == 129 ? 1 : 0, DEC); #endif if (r == 128) { mcp4131_detected = 1; } else if (r != 129) { return 0; //error - the value should be either 128 (clamped by mcp4313) or 129 (mcp5151) } mcp4131_write(ADDR_WIPER, POT_DEFAULT_VALUE); #if POT_WIPER_ENABLED mcp4131_enableWiper(); #endif return 1; } #endif