Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define F_CPU 16000000
- #include <avr/io.h>
- #include <util/delay.h>
- #define CSBAR 0 //PC0 for CS
- #define SKBAR 1 //PC1 for SK
- #define DIO 2 //PC2 for DIO
- #define Tclk 2 // clock period 4us
- //ASSUMES PORTC USED FOR ALL CSBAR, SKBAR, DIO
- //REQUIRES MODIFICATION
- void write16bit(uint16_t data){
- for(uint8_t i = 0; i < 16; i++){ // write out data onto DIO
- if(data & (0x8000)){ // set DIO pin to data MSB
- PORTC |= (1 << DIO);
- }else{
- PORTC &= ~(1 << DIO);
- }
- data = data << 1; // shift MSB next in line
- PORTC |= (1 << SKBAR); // pulse clock high
- _delay_us(Tclk);
- PORTC &= ~(1 << SKBAR); // set clock low
- _delay_us(Tclk);
- }
- }
- void WriteEnable(uint8_t status){ // status = 1 for write, 0 for read
- PORTC &= ~(1 << CSBAR); // enable chip
- PORTC &= ~(1 << SKBAR); // clock must start low
- _delay_us(Tclk);
- write16bit(status ? 0xA300 : 0xA000); // 1010 0011 XXXX XXXX per datasheet is write
- // 1010 0000 XXXX XXXX per datasheet is read
- PORTC |= (1 << SKBAR); // end clock high
- _delay_us(Tclk);
- PORTC |= (1 << CSBAR); // set CS off
- _delay_us(5*Tclk); // short delay to keep CS high for a required amount of time, can likely be lessened
- }
- uint8_t WCRead(){ // return wiper position 0-127
- PORTC &= ~(1 << CSBAR); // enable chip
- PORTC &= ~(1 << SKBAR); // clock must start low
- _delay_us(Tclk);
- write16bit(0xAB00); // 1010 1011 XXXX XXXX per datasheet
- DDRC &= ~(1 << DIO); // set DIO for reading
- uint8_t buf = 0; // output buffer
- for(uint8_t i = 0; i < 8; i++){ // read 8 bits in via DIO
- if(PINC & (1 << DIO)){ // read bit is a 1
- buf |= (1 << i);
- }
- PORTC |= (1 << SKBAR); // set clock high
- _delay_us(Tclk);
- PORTC &= ~(1 << SKBAR); // set clock low
- _delay_us(Tclk);
- }
- DDRC |= (1 << DIO); // set DIO for writing (rest of commands)
- PORTC |= (1 << SKBAR) | (1 << CSBAR); // end clock high and turn chip off
- return buf;
- }
- uint8_t WCWrite(uint8_t step){ // write wiper, step 0 to 127
- step = (step & 0xF0) >> 4 | (step & 0x0F) << 4; // byte indicating step count is sent out LSB-first
- step = (step & 0xCC) >> 2 | (step & 0x33) << 2; // meaning it must be reversed as commands are sent MSB-first
- step = (step & 0xAA) >> 1 | (step & 0x55) << 1;
- uint16_t data_fix = step << 8; // needs empty byte afterward
- PORTC &= ~(1 << CSBAR); // enable chip
- PORTC &= ~(1 << SKBAR); // set clock low
- _delay_us(Tclk);
- write16bit(0xA600); // send write command then empty address byte
- write16bit(data_fix); // send wiper value then empty unused byte
- PORTC |= (1 << SKBAR); // datasheet shows two extra empty clock pulses
- _delay_us(Tclk); // seem to be ignored, but kept just in case
- PORTC &= ~(1 << SKBAR);
- _delay_us(Tclk);
- PORTC |= (1 << SKBAR); // end clock high
- _delay_us(Tclk);
- PORTC |= (1 << CSBAR); // disable chip
- }
- int main(){
- DDRC = (1 << CSBAR) | (1 << SKBAR) | (1 << DIO);
- PORTC = (1 << CSBAR) | (1 << SKBAR);
- // example read
- uint8_t read_wiper = WCRead(); // chip starts in read-mode so this is okay
- // can use tmk/qmk to write value as keystrokes to screen
- // is good to know default value
- // example write
- WriteEnable(1); // put chip into write mode
- _delay_us(Tclk*5); // let settle, just in case, likely not needed
- WCWrite(0x40); // uses example value 0x40, my "default" value was 0x27 but it likely differs per-board
- _delay_us(Tclk*5); // let settle, likely not needed
- WriteEnable(0); // put back in read_mode
- // here would be a good place to verify that it wrote correctly with WCRead()
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement