1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-23 08:06:13 +01:00

Fix read operations on I2CManager for SAMD

This commit is contained in:
Neil McKechnie 2023-01-31 00:36:57 +00:00
parent d0ce59b19f
commit 291a331f3e

View File

@ -1,6 +1,6 @@
/* /*
* © 2022 Paul M Antoine * © 2022 Paul M Antoine
* © 2021, Neil McKechnie * © 2023, Neil McKechnie
* All rights reserved. * All rights reserved.
* *
* This file is part of CommandStation-EX * This file is part of CommandStation-EX
@ -107,8 +107,8 @@ void I2CManagerClass::I2C_init()
s->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_MODE( I2C_MASTER_OPERATION )/* | s->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_MODE( I2C_MASTER_OPERATION )/* |
SERCOM_I2CM_CTRLA_SCLSM*/ ; SERCOM_I2CM_CTRLA_SCLSM*/ ;
// Enable Smart mode and Quick Command // Enable Smart mode (but not Quick Command)
s->I2CM.CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN | SERCOM_I2CM_CTRLB_QCEN; s->I2CM.CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN;
#if defined(I2C_USE_INTERRUPTS) #if defined(I2C_USE_INTERRUPTS)
// Setting NVIC // Setting NVIC
@ -141,7 +141,7 @@ void I2CManagerClass::I2C_init()
PORT->Group[g_APinDescription[PIN_WIRE_SCL].ulPort].PINCFG[g_APinDescription[PIN_WIRE_SCL].ulPin].reg = PORT->Group[g_APinDescription[PIN_WIRE_SCL].ulPort].PINCFG[g_APinDescription[PIN_WIRE_SCL].ulPin].reg =
PORT_PINCFG_DRVSTR | PORT_PINCFG_PULLEN | PORT_PINCFG_PMUXEN; PORT_PINCFG_DRVSTR | PORT_PINCFG_PULLEN | PORT_PINCFG_PMUXEN;
PORT->Group[g_APinDescription[PIN_WIRE_SDA].ulPort].PINCFG[g_APinDescription[PIN_WIRE_SDA].ulPin].reg = PORT->Group[g_APinDescription[PIN_WIRE_SDA].ulPort].PINCFG[g_APinDescription[PIN_WIRE_SDA].ulPin].reg =
PORT_PINCFG_DRVSTR | PORT_PINCFG_PULLEN | PORT_PINCFG_PMUXEN; PORT_PINCFG_DRVSTR | PORT_PINCFG_PULLEN | PORT_PINCFG_PMUXEN;
} }
/*************************************************************************** /***************************************************************************
@ -152,18 +152,21 @@ void I2CManagerClass::I2C_sendStart() {
bytesToReceive = currentRequest->readLen; bytesToReceive = currentRequest->readLen;
// We may have initiated a stop bit before this without waiting for it. // We may have initiated a stop bit before this without waiting for it.
// Wait for stop bit to be sent before sending start. // However, the state machine ensures that the start bit isn't sent
while (s->I2CM.STATUS.bit.BUSSTATE == 0x2); // until the stop bit is complete.
//while (s->I2CM.STATUS.bit.BUSSTATE == 0x2);
// If anything to send, initiate write. Otherwise initiate read. // If anything to send, initiate write. Otherwise initiate read.
if (operation == OPERATION_READ || ((operation == OPERATION_REQUEST) && !bytesToSend)) if (operation == OPERATION_READ || ((operation == OPERATION_REQUEST) && !bytesToSend))
{ {
// Wait while the I2C bus is BUSY
//while (s->I2CM.STATUS.bit.BUSSTATE != 0x1);
// Send start and address with read/write flag or'd in // Send start and address with read/write flag or'd in
s->I2CM.ADDR.bit.ADDR = (currentRequest->i2cAddress << 1) | 1; s->I2CM.ADDR.bit.ADDR = (currentRequest->i2cAddress << 1) | 1;
} }
else { else {
// Wait while the I2C bus is BUSY // Wait while the I2C bus is BUSY
while (s->I2CM.STATUS.bit.BUSSTATE != 0x1); //while (s->I2CM.STATUS.bit.BUSSTATE != 0x1);
s->I2CM.ADDR.bit.ADDR = (currentRequest->i2cAddress << 1ul) | 0; s->I2CM.ADDR.bit.ADDR = (currentRequest->i2cAddress << 1ul) | 0;
} }
} }
@ -203,14 +206,11 @@ void I2CManagerClass::I2C_handleInterrupt() {
state = I2C_STATUS_NEGATIVE_ACKNOWLEDGE; state = I2C_STATUS_NEGATIVE_ACKNOWLEDGE;
} else if (bytesToSend) { } else if (bytesToSend) {
// Acked, so send next byte // Acked, so send next byte
if (currentRequest->operation == OPERATION_SEND_P) s->I2CM.DATA.bit.DATA = currentRequest->writeBuffer[txCount++];
s->I2CM.DATA.bit.DATA = GETFLASH(currentRequest->writeBuffer + (txCount++));
else
s->I2CM.DATA.bit.DATA = currentRequest->writeBuffer[txCount++];
bytesToSend--; bytesToSend--;
} else if (bytesToReceive) { } else if (bytesToReceive) {
// Last sent byte acked and no more to send. Send repeated start, address and read bit. // Last sent byte acked and no more to send. Send repeated start, address and read bit.
s->I2CM.ADDR.bit.ADDR = (currentRequest->i2cAddress << 1) | 1; s->I2CM.ADDR.bit.ADDR = (currentRequest->i2cAddress << 1) | 1;
} else { } else {
// No more data to send/receive. Initiate a STOP condition. // No more data to send/receive. Initiate a STOP condition.
I2C_sendStop(); I2C_sendStop();
@ -218,25 +218,16 @@ void I2CManagerClass::I2C_handleInterrupt() {
} }
} else if (s->I2CM.INTFLAG.bit.SB) { } else if (s->I2CM.INTFLAG.bit.SB) {
// Master read completed without errors // Master read completed without errors
if (bytesToReceive) { if (bytesToReceive == 1) {
s->I2CM.CTRLB.bit.ACKACT = 1; // NAK final byte
I2C_sendStop(); // send stop
currentRequest->readBuffer[rxCount++] = s->I2CM.DATA.bit.DATA; // Store received byte
bytesToReceive = 0;
state = I2C_STATUS_OK; // done
} else if (bytesToReceive) {
s->I2CM.CTRLB.bit.ACKACT = 0; // ACK all but final byte
currentRequest->readBuffer[rxCount++] = s->I2CM.DATA.bit.DATA; // Store received byte currentRequest->readBuffer[rxCount++] = s->I2CM.DATA.bit.DATA; // Store received byte
bytesToReceive--; bytesToReceive--;
} else {
// Buffer full, issue nack/stop
s->I2CM.CTRLB.bit.ACKACT = 1;
I2C_sendStop();
state = I2C_STATUS_OK;
}
if (bytesToReceive) {
// PMA - I think Smart Mode means we have nothing to do...
// More bytes to receive, issue ack and start another read
}
else
{
// Transaction finished, issue NACK and STOP.
s->I2CM.CTRLB.bit.ACKACT = 1;
I2C_sendStop();
state = I2C_STATUS_OK;
} }
} }
} }