2017-01-03 12:25 PM
Hi, all. I'm using the STM32F7 Discovery board. (
STM32F746NGH6
chip) and am trying to implement an I2C driver (bare metal) for the I2C1 port on pins PB8/PB9 which are brought out to the Arduino header so I can connect those lines to an external board.I just can't get any bus activity, verified by a logic analyzer. No SCL clocks, no data being transmitted. I've checked and double and triple checked the discovery board schematics and those pins are only connected to 2.7KOhm pull-ups on board and the DCMI camera connector.
I have attached my code below. I have stripped down the I2CWriteBytes function to just transmit a single byte (master mode) so I can see if the bus is getting driven at all. The code returns with the timeout errors.
The GPIOSetAltFunc function is a single line call to my own GPIO code which has been proven to work elsewhere in the system.
The I2C peripheral clock is PB1 (54MHz) and the bus speed should be around 100KHz, according to STM's I2C config tool. I cannot verify the bus speed since the SCL line does not clock anything.Can anyone spot what I am missing? Thanks very much.void InitI2CBus(I2C_TypeDef *I2Cx)
{ // Enable the I2C1 PB1 clock. RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; GPIOSetAltFunc(GPIOB, GPIO_Pin_8 | GPIO_Pin_9, GPIO_PuPd_NOPULL, GPIO_OType_OD, GPIO_AF4_I2C1);
// Disable this I2C instance
I2Cx->CR1 &= ~I2C_CR1_PE;/*---------------------------- I2Cx TIMINGR Configuration ------------------*/
// Configure I2C Bus Frequency. // These numbers are from CubeMX on 54MHz clock and 100KHz I2C bus speed. // I2Cx->TIMINGR = 0x20404768; // From CubeMX on 54MHz clock and 100KHz I2C bus speed. I2Cx->TIMINGR = 0x10907295; // From I2C Timing tool Excel spreadsheet (AN4235).
// Configure I2Cx->CR1: Control Register1
I2Cx->CR1 = 0;// Configure I2Cx->CR2: Control Register2
I2Cx->CR2 = 0;// Configure I2Cx: Own Address1 (0) and ack own address1 mode
I2Cx->OAR1 = 0;// Configure I2Cx: Dual mode and Own Address2
I2Cx->OAR2 = 0;// Clear Interrupt and Status register
I2Cx->ISR = 0;// Enable I2Cx Peripheral
I2Cx->CR1 |= I2C_CR1_PE;}I2C_StatusTypeDef I2CWriteBytes(I2C_TypeDef *I2Cx, U8 slaveDeviceAddr, U8 slaveRegisterAddr, U8 regAddrSize, U8 *writeBuff, U16 numBytesToWrite)
{ uartprint(DEBUG_UART, 'I2C1WriteBytes-0\r\n');// Is I2C bus BUSY?
if ((I2Cx->ISR & I2C_ISR_BUSY) == I2C_ISR_BUSY) return I2C_BUSY_STATE;uartprint(DEBUG_UART, 'I2C1WriteBytes-1\r\n');
// Setup slaveDeviceAddr address for write and set NBYTES in CR2 to 1
// Need to set the start bit AFTER all these bits are set. // I2Cx->CR2 = I2C_CR2_CFG_SOFTEND_WRITE(slaveDeviceAddr, 1); U3 numBytes = 1; I2Cx->CR2 = (slaveDeviceAddr & I2C_CR2_SADD) | ((numBytes << 16 ) & I2C_CR2_NBYTES);// Send START condition
I2Cx->CR2 |= I2C_CR2_START;// Wait for I2C_ISR_TXIS flag - Transmit is ready to start
U32 I2CTimeout = I2C_LONG_TIMEOUT; while ((I2Cx->ISR & I2C_ISR_TXIS) != I2C_ISR_TXIS) { if (I2CTimeout-- == 0) return I2C_TIMEOUT_UserCallback('I2CWriteBytes-1'); }// uartprintf(DEBUG_UART, 'I2C1WriteBytes-2\r\n');
// Now transmit the slaveDeviceAddr
I2Cx->TXDR = slaveDeviceAddr;// Test on I2C_ISR_TC - Transmit complete (i.e. 1 Byte sent)
I2CTimeout = I2C_LONG_TIMEOUT; while ((I2Cx->ISR & I2C_ISR_TC) != I2C_ISR_TC) { if (I2CTimeout-- == 0) return I2C_TIMEOUT_UserCallback('I2C1WriteBytes-2'); }// TEST ONLY
// Send STOP condition I2Cx->CR2 |= I2C_CR2_STOP;uartprint(DEBUG_UART, 'I2C1WriteBytes-3\r\n');
return I2C_TESTERROR_STATE;}2017-01-04 03:28 AM
Hi
Harrison.David.002
I have moved your post to the
where product related questions are posted. All the best finding the assistance you need.Thanks
Oli
2017-01-04 08:39 AM
If using the debugger, check the peripheral registers (if all look like 0x00 it means the peripheral was not clock enabled)
Have you also checked the GPIO register in debugger? Same check, check the alternate function is correct.
If the pins don't toggle, I would manually in the debugger toggle the pin a Push pull output high and low to really make sure.
In a first step, it is also possible to try out a SW I2C with GPIO which is in the I2C
Some clues here:
2017-01-06 07:29 AM
So I first of al checked out the port pins by setting them as regular push-pull GPIO outputs and I could toggle them at will, then set them as open drain and I could still toggle them so the pull-up resistors were working. Then I checked my pin initialization code (which happens much earlier than the call to InitI2CBus()). It turns out that I was inadvertently setting those pins as push-pull GPIO outputs soon after the start of main() which meant those lines were being pulled low. But since they had pull-up resistors, as soon as power was applied, the lines would have been high, then were pulled low. It was that high to low transition which was triggering my logic analyzer and the lines stayed low for about 200ms until the InitI2CBus() function was called when they would be correctly configured as open drain and therefore go high again.
It was that 200ms period of both lines staying low that fooled me into thinking nothing was happening. After I removed the erroneous initialization as push-pull GPIO outputs and re-configured the trigger conditions for my logic analyzer, I was able to see some bus activity. It wasn't the right activity, but at least I got some. Now I should be able to find out what is wrong now that I can see what activity is transpiring on the bus. I am using an I2C interpreter in the logic analyzer so I see the data values being transmitted, or received.