Dear All,
After getting a spi bus working with your help, I just could not leave it alone and managed to get stuck on trying to write my own peripheral handler for an I2C master.
Here is my code:
The function which transmits 4 12bit values, via 6 8bit transmitions:
BOOL motor_update(int mfl, int mfr, int mbl, int mbr) {
char msg1 = ((0b111111110000 & mfl) >> 4);
char msg2 = ((0b1111 & mfl) << 4) | ((0b1111000000000 & mfr) >> 8);
char msg3 = ((0b11111111 & mfr));
char msg4 = ((0b111111110000 & mbl) >> 4);
char msg5 = ((0b1111 & mbl) << 4) | ((0b111100000000 & mbr) >> 8);
char msg6 = (IIC1, ((0b11111111 & mbr)));
IIC_start(IIC1);
while (IIC_status(IIC1, IIC_STAT_START)) {
;
}
//Send Address, wait
IIC_address(IIC1, IIC_ADR_INT, IIC_WRITE);
while(IIC_status(IIC1, IIC_STAT_TRANSMIT_FULL) & IIC_status(IIC1, IIC_STAT_TRANSMIT)){;}
if(IIC_status(IIC1,IIC_STAT_ACK)){
terminate();
return TRUE;
}
//Send ms1, wait
IIC_put(IIC1, msg1);
while(IIC_status(IIC1, IIC_STAT_TRANSMIT_FULL) & IIC_status(IIC1, IIC_STAT_TRANSMIT)){;}
if(IIC_status(IIC1,IIC_STAT_ACK)){
terminate();
return TRUE;
}
//Send ms2, wait
IIC_put(IIC1, msg2);
while(IIC_status(IIC1, IIC_STAT_TRANSMIT_FULL) & IIC_status(IIC1, IIC_STAT_TRANSMIT)){;}
if(IIC_status(IIC1,IIC_STAT_ACK)){
terminate();
return TRUE;
}
//Send ms3, wait
IIC_put(IIC1, msg3);
while(IIC_status(IIC1, IIC_STAT_TRANSMIT_FULL) & IIC_status(IIC1, IIC_STAT_TRANSMIT)){;}
if(IIC_status(IIC1,IIC_STAT_ACK)){
terminate();
return TRUE;
}
//Send ms4, wait
IIC_put(IIC1, msg4);
while(IIC_status(IIC1, IIC_STAT_TRANSMIT_FULL) & IIC_status(IIC1, IIC_STAT_TRANSMIT)){;}
if(IIC_status(IIC1,IIC_STAT_ACK)){
terminate();
return TRUE;
}
//Send ms5, wait
IIC_put(IIC1, msg5);
while(IIC_status(IIC1, IIC_STAT_TRANSMIT_FULL) & IIC_status(IIC1, IIC_STAT_TRANSMIT)){;}
if(IIC_status(IIC1,IIC_STAT_ACK)){
terminate();
return TRUE;
}
//Send ms6, wait
IIC_put(IIC1, msg6);
while(IIC_status(IIC1, IIC_STAT_TRANSMIT_FULL) & IIC_status(IIC1, IIC_STAT_TRANSMIT)){;}
if(IIC_status(IIC1,IIC_STAT_ACK)){
terminate();
return TRUE;
}
//Stop
IIC_stop(IIC1);
while (IIC_status(IIC1, IIC_STAT_STOP)) {
;
}
}
void terminate(){
IIC_stop(IIC1);
while(IIC_status(IIC1, IIC_STAT_STOP)){;}
}
Here is the code for my IIC methods, which I call in the above function:
typedef enum {
IIC_READ = 1,
IIC_WRITE = 0
} IIC_OPERATION;
typedef enum {
//A0000000 00000000 XXXXXXXX XXXXXXXX
//A: 1 = CON register, 0 = Status register
//X: Bit mask
IIC_STAT_CLKSTRETCH = 0b10000000000000000000000001000000,
IIC_STAT_RECEIVE = 0b10000000000000000000000000001000,
IIC_STAT_START = 0b10000000000000000000000000000001,
IIC_STAT_STOP = 0b10000000000000000000000000000100,
IIC_STAT_RESTART = 0b10000000000000000000000000000010,
IIC_STAT_ACK_SENT = 0b10000000000000000000000000010000,
IIC_STAT_ACK = 0b00000000000000001000000000000000,
IIC_STAT_TRANSMIT = 0b00000000000000000100000000000000,
IIC_STAT_MASTER_COLLISION = 0b00000000000000000000010000000000,
IIC_STAT_GENERAL_CALL = 0b00000000000000000000001000000000,
IIC_STAT_10BIT_MATCH = 0b00000000000000000000000100000000,
IIC_STAT_WRITE_COLLOSION = 0b00000000000000000000000010000000,
IIC_STAT_RECEIVE_OVERFLOW = 0b00000000000000000000000001000000,
IIC_STAT_DATA_NADDRESS = 0b00000000000000000000000000100000,
IIC_STAT_STOP_DET = 0b00000000000000000000000000010000,
IIC_STAT_START_DET = 0b00000000000000000000000000001000,
IIC_STAT_READ_NWRITE_DET = 0b00000000000000000000000000000100,
IIC_STAT_RECEIVE_FULL = 0b00000000000000000000000000000010,
IIC_STAT_TRANSMIT_FULL = 0b00000000000000000000000000000001,
} IIC_STATUS;
void IIC_stop(IIC_CHANNEL channel) {
if (channel == IIC2) {
I2C2CONbits.PEN = 1;
} else {
//Default to Channel 1
I2C1CONbits.PEN = 1;
}
}
void IIC_start(IIC_CHANNEL channel) {
if (channel == IIC2) {
I2C2CONbits.SEN = 1;
} else {
//Default to Channel 1
I2C1CONbits.SEN = 1;
}
}
BOOL IIC_status(IIC_CHANNEL channel, IIC_STATUS stat){
if(channel == IIC2){
if((stat & 0x80000000)){
return ((I2C2CON) & (0x7FFFFFFF & stat));
} else {
return ((I2C2STAT) & (0x7FFFFFFF & stat));
}
} else{
if((stat & 0x80000000)){
return ((I2C1CON) & (0x7FFFFFFF & stat));
} else {
return ((I2C1STAT) & (0x7FFFFFFF & stat));
}
}
}
void IIC_address(IIC_CHANNEL channel, char address, IIC_OPERATION op){
char value = ((address & 0b1111111) << 1) | op;
IIC_put(channel, value);
}
void IIC_put(IIC_CHANNEL channel,char data) {
if(channel == IIC2){
I2C2TRN = data;
} else {
//default to channel 1
I2C1TRN = data;
}
}
My issue is that, according to my scope, only the address + r/w bit is being sent, immediately followed by a Stop state:
I am however quite certain that the function does not exit right after the IIC_address call, as the terminate method is never executed (checked by placing a stop point there) and the the method does not return TRUE, which would indicate an error.
My best guess is that I am polling the wrong bits to check for completion, which results in all the future writes to the I2C1BUF being ignore, and then the STOP bit at the end of the function executing.
In other words, I suspect an issue with:
while (IIC_status(IIC1, IIC_STAT_TRANSMIT_FULL)){ ...
which is simply a complicated way of writing:
while(I2C1STATbits.TBF){...
I am slightly confused what I should be polling, as the data sheet mentions booth the I2C1STATbits.TBF and I2C1CONbits.TRSTAT...
Any help would be greatly appreciated.
Side Note:
XC32 Complier
PIC32MX120F064H