Skip to content

I2C fix: Idle_delay added in between commands, SPI slave Fix: Format function modified and SPISLAVE enabled #3611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions targets/TARGET_ONSEMI/TARGET_NCS36510/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,18 @@
#define I2C_APB_CLK_DIVIDER_VAL_MASK 0x1FE0

/* Error check */
#define I2C_UFL_CHECK (d->membase->STATUS.WORD & 0x80)
#define FIFO_OFL_CHECK (d->membase->STATUS.WORD & 0x10)
#define I2C_BUS_ERR_CHECK (d->membase->STATUS.WORD & 0x04)
#define RD_DATA_READY (d->membase->STATUS.WORD & 0x02)
#define I2C_UFL_CHECK (obj->membase->STATUS.WORD & 0x80)
#define I2C_FIFO_FULL (obj->membase->STATUS.WORD & 0x20)
#define FIFO_OFL_CHECK (obj->membase->STATUS.WORD & 0x10)
#define I2C_BUS_ERR_CHECK (obj->membase->STATUS.WORD & 0x04)
#define RD_DATA_READY (obj->membase->STATUS.WORD & 0x02)
#define I2C_FIFO_EMPTY (obj->membase->STATUS.WORD & 0x01)

#define I2C_API_STATUS_SUCCESS 0
#define PAD_REG_ADRS_BYTE_SIZE 4

#define SEND_COMMAND(cmd) while(!I2C_FIFO_EMPTY); wait_us(1); obj->membase->CMD_REG = cmd;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@0xc0170 Do we have a policy for using the wait* api in the hal? Is it fine to use or do we typically just busy loop instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used in HAL for some targets .

I wonder why this timeout is needed .


/** Init I2C device.
* @details
* Sets the necessary registers. The baud rate is set default to 100K
Expand Down Expand Up @@ -154,4 +158,4 @@ extern int32_t fI2cReadB(i2c_t *d, char *buf, int len);
*/
extern int32_t fI2cWriteB(i2c_t *d, const char *buf, int len);

#endif /* I2C_H_ */
#endif /* I2C_H_ */
9 changes: 4 additions & 5 deletions targets/TARGET_ONSEMI/TARGET_NCS36510/i2c_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "i2c.h"
#include "i2c_api.h"
#include "wait_api.h"

#define I2C_READ_WRITE_BIT_MASK 0xFE

Expand Down Expand Up @@ -151,10 +152,10 @@ int i2c_byte_read(i2c_t *obj, int last) /* TODO return size can be uint8_t */
}
if(last) {
/* ACK */
obj->membase->CMD_REG = I2C_CMD_WDAT0;
SEND_COMMAND(I2C_CMD_WDAT0);
} else {
/* No ACK */
obj->membase->CMD_REG = I2C_CMD_WDAT1;
SEND_COMMAND(I2C_CMD_WDAT1);
}
return data;
}
Expand All @@ -168,8 +169,6 @@ int i2c_byte_write(i2c_t *obj, int data)
return Count;
}

obj->membase->CMD_REG = I2C_CMD_VRFY_ACK; /* Verify ACK */

while(obj->membase->STATUS.WORD & I2C_STATUS_CMD_FIFO_OFL_BIT); /* Wait till command overflow ends */

if(obj->membase->STATUS.WORD & I2C_STATUS_BUS_ERR_BIT) {
Expand All @@ -181,4 +180,4 @@ int i2c_byte_write(i2c_t *obj, int data)
}
}

#endif /* DEVICE_I2C */
#endif /* DEVICE_I2C */
55 changes: 33 additions & 22 deletions targets/TARGET_ONSEMI/TARGET_NCS36510/ncs36510_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
*/
#if DEVICE_I2C
#include "i2c.h"
#include "wait_api.h"

/* See i2c.h for details */
void fI2cInit(i2c_t *obj,PinName sda,PinName scl)
Expand Down Expand Up @@ -135,15 +136,15 @@ void fI2cFrequency(i2c_t *obj, uint32_t hz)
int32_t fI2cStart(i2c_t *obj)
{
/* Send start bit */
obj->membase->CMD_REG = I2C_CMD_START;
SEND_COMMAND(I2C_CMD_START)
return I2C_API_STATUS_SUCCESS;
}

/* See i2c.h for details */
int32_t fI2cStop(i2c_t *obj)
{
/* Send stop bit */
obj->membase->CMD_REG = I2C_CMD_STOP;
SEND_COMMAND(I2C_CMD_STOP);
if (obj->membase->STATUS.WORD & (I2C_STATUS_CMD_FIFO_FULL_BIT |
I2C_STATUS_CMD_FIFO_OFL_BIT |
I2C_STATUS_BUS_ERR_BIT)) {
Expand All @@ -154,23 +155,26 @@ int32_t fI2cStop(i2c_t *obj)
}

/* See i2c.h for details */
int32_t fI2cReadB(i2c_t *d, char *buf, int len)
int32_t fI2cReadB(i2c_t *obj, char *buf, int len)
{
int32_t read = 0;

while (read < len) {
/* Send read command */
d->membase->CMD_REG = I2C_CMD_RDAT8;
SEND_COMMAND(I2C_CMD_RDAT8);
while(!RD_DATA_READY) {
if (I2C_BUS_ERR_CHECK) {
/* Bus error occured */
return I2C_ERROR_BUS_BUSY;
}
}
buf[read++] = d->membase->RD_FIFO_REG; /**< Reading 'read FIFO register' will clear status register */
buf[read++] = obj->membase->RD_FIFO_REG; /**< Reading 'read FIFO register' will clear status register */

if(!(read>=len)) { /* No ACK will be generated for the last read, upper level I2C protocol should generate */
d->membase->CMD_REG=I2C_CMD_WDAT0; /* TODO based on requirement generate ACK or NACK Based on the requirement. */
SEND_COMMAND(I2C_CMD_WDAT0); /* TODO based on requirement generate ACK or NACK Based on the requirement. */
} else {
/* No ack */
SEND_COMMAND(I2C_CMD_WDAT1);
}

/* check for FIFO underflow */
Expand All @@ -187,42 +191,49 @@ int32_t fI2cReadB(i2c_t *d, char *buf, int len)
}

/* See i2c.h for details */
int32_t fI2cWriteB(i2c_t *d, const char *buf, int len)
int32_t fI2cWriteB(i2c_t *obj, const char *buf, int len)
{
int32_t write = 0;

while (write < len) {
/* Send write command */
d->membase->CMD_REG = I2C_CMD_WDAT8;
SEND_COMMAND(I2C_CMD_WDAT8);

if(buf[write] == I2C_CMD_RDAT8) {
/* SW work around to counter FSM issue. If the only command in the CMD FIFO is the WDAT8 command (data of 0x13)
then as the command is read out (i.e. the FIFO goes empty), the WDAT8 command will be misinterpreted as a
RDAT8 command by the data FSM; resulting in an I2C bus error (NACK instead of an ACK). */
/* Send 0x13 bit wise */
d->membase->CMD_REG = I2C_CMD_WDAT0;
d->membase->CMD_REG = I2C_CMD_WDAT0;
d->membase->CMD_REG = I2C_CMD_WDAT0;
d->membase->CMD_REG = I2C_CMD_WDAT1;

d->membase->CMD_REG = I2C_CMD_WDAT0;
d->membase->CMD_REG = I2C_CMD_WDAT0;
d->membase->CMD_REG = I2C_CMD_WDAT1;
d->membase->CMD_REG = I2C_CMD_WDAT1;
SEND_COMMAND(I2C_CMD_WDAT0);

SEND_COMMAND(I2C_CMD_WDAT0);

SEND_COMMAND(I2C_CMD_WDAT0);

SEND_COMMAND(I2C_CMD_WDAT1);

SEND_COMMAND(I2C_CMD_WDAT0);

SEND_COMMAND(I2C_CMD_WDAT0);

SEND_COMMAND(I2C_CMD_WDAT1);

SEND_COMMAND(I2C_CMD_WDAT1);
} else {
/* Send data */
d->membase->CMD_REG = buf[write++];
SEND_COMMAND(buf[write++]);
}
d->membase->CMD_REG = I2C_CMD_VRFY_ACK; /* TODO Verify ACK based on requirement, Do we need? */

while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
SEND_COMMAND(I2C_CMD_VRFY_ACK); /* TODO Verify ACK based on requirement, Do we need? */

if (I2C_BUS_ERR_CHECK) {
/* Bus error */
return I2C_ERROR_BUS_BUSY;
}

while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
}

return write;
}

#endif /* DEVICE_I2C */
#endif /* DEVICE_I2C */
14 changes: 8 additions & 6 deletions targets/TARGET_ONSEMI/TARGET_NCS36510/spi_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,16 @@ void spi_free(spi_t *obj)
void spi_format(spi_t *obj, int bits, int mode, int slave)
{
/* Clear word width | Slave/Master | CPOL | CPHA | MSB first bits in control register */
obj->membase->CONTROL.WORD &= ~(uint32_t)((True >> SPI_WORD_WIDTH_BIT_POS) |
(True >> SPI_SLAVE_MASTER_BIT_POS) |
(True >> SPI_CPOL_BIT_POS) |
(True >> SPI_CPHA_BIT_POS));
obj->membase->CONTROL.WORD &= ~(uint32_t)((True << SPI_WORD_WIDTH_BIT_POS) |
(True << SPI_SLAVE_MASTER_BIT_POS) |
(True << SPI_CPOL_BIT_POS) |
(True << SPI_CPHA_BIT_POS));

/* Configure word width | Slave/Master | CPOL | CPHA | MSB first bits in control register */
obj->membase->CONTROL.WORD |= (uint32_t)(((bits >> 0x4) >> 6) | (!slave >> 5) |
((mode >> 0x1) >> 4) | ((mode & 0x1) >> 3));
obj->membase->CONTROL.WORD |= (uint32_t)(((bits >> 0x4) << SPI_WORD_WIDTH_BIT_POS) |
(!slave << SPI_SLAVE_MASTER_BIT_POS) |
((mode >> 0x1) << SPI_CPOL_BIT_POS) |
((mode & 0x1) << SPI_CPHA_BIT_POS));
}

void spi_frequency(spi_t *obj, int hz)
Expand Down
2 changes: 1 addition & 1 deletion targets/targets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2568,7 +2568,7 @@
"post_binary_hook": {"function": "NCS36510TargetCode.ncs36510_addfib"},
"macros": ["CM3", "CPU_NCS36510", "TARGET_NCS36510", "LOAD_ADDRESS=0x3000"],
"supported_toolchains": ["GCC_ARM", "ARM", "IAR"],
"device_has": ["ANALOGIN", "SERIAL", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "LOWPOWERTIMER", "TRNG"],
"device_has": ["ANALOGIN", "SERIAL", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "LOWPOWERTIMER", "TRNG", "SPISLAVE"],
"device_name": "NCS36510",
"release_versions": ["2", "5"]
},
Expand Down