Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F0 и I2C
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
toweroff
Добрый день

Во всех примерах, какие находились на просторах, чтение/запись осуществляется по одному байту.
Теоретически, ничего сложного - "задвинуть" количество байт в CR2 и потом пиши/читай
Но что-то не сходится. После записи байта никакие флаги не возводятся, как определить готовность к следующему байту? Да и с чтением та же петрушка
Как вообще это нужно делать?

Спасибо
smalcom
там весёлый I2C. Тут недавно проскакивала тема про это, в ней и исходники есть.
Суть в том, что правильно(по рек.произв.) алгоритм отправки состоит из трёх ветвей: отправить один байт, отправить два, отправить больше двух.
toweroff
В общем у меня вот такое родилось, работает. На шине одновременно висят EEPROM 24LC16 и LIS3DH

CODE

// ==================================================
void I2C_Start_Direction_Adress_Size (I2C_TypeDef* Port, uint32_t Direction, uint8_t Adress, uint8_t Size)
{
Port->CR2 &= ~I2C_CR2_AUTOEND; // Stop by siftware
Port->CR2 &= ~I2C_CR2_RELOAD; // No reload
if (Direction == I2C_CR2_RD_WRN) Port->CR2 |= I2C_CR2_RD_WRN; // receive mode
else Port->CR2 &= ~I2C_CR2_RD_WRN; // transmit mode
Port->CR2 &= ~I2C_CR2_NBYTES; // clear NBYTES field
Port->CR2 |= Size<<16; // Set NBYTES
Port->CR2 &= ~I2C_CR2_SADD; // clear slave address field
Port->CR2 |= Adress; // Set slave address
Port->CR2 |= I2C_CR2_START; // Transmit START bit
while ((Port->ISR & I2C_ISR_BUSY)==0) {}; // Wait for done
}
// ==================================================


// ==================================================
void I2C_Stop (I2C_TypeDef* Port)
{
Port->CR2 |= I2C_CR2_STOP; // Stop to bus
while (Port->ISR & I2C_ISR_BUSY) {}; // wait for stop transmitted
// Clear flags
Port->ICR |= I2C_ICR_STOPCF;
Port->ICR |= I2C_ICR_NACKCF;
// Clear errors flags
if (Port->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR))
{
Port->ICR |= I2C_ICR_ARLOCF;
Port->ICR |= I2C_ICR_BERRCF;
}
}
// ==================================================



i2c_operate_t I2C_Operate(I2C_TypeDef* Port, uint8_t addr, void* trsm, uint8_t tcount, void* rcv, uint8_t rcount)
{
uint8_t *u8_ptr;
uint32_t status;

if (((tcount==0) && (rcount==0)) || (tcount)) // tcount== 0 and rcount==0 for device presence check
{
I2C_Start_Direction_Adress_Size(Port, 0, addr, tcount);
// Check for status
while (!(Port->ISR & (I2C_ISR_TC | I2C_ISR_TXIS | I2C_ISR_NACKF) && (Port->ISR & I2C_ISR_BUSY))) {};

if (Port->ISR & I2C_ISR_NACKF)
{
I2C_Stop(Port);
return I2C_OPERATE_NO_DEVICE;
}
}

// Transmit part
if (tcount)
{
u8_ptr = (uint8_t*)trsm;
while ((((Port->ISR & I2C_ISR_TC)==0) && ((Port->ISR & I2C_ISR_NACKF)==0)) && (Port->ISR & I2C_ISR_BUSY))
{
if (Port->ISR & I2C_ISR_TXIS) Port->TXDR = *u8_ptr++; // Send data
}

status = Port->ISR;
if (status & (I2C_ICR_ARLOCF | I2C_ICR_BERRCF | I2C_ISR_NACKF)) // some errors
{
I2C_Stop(Port);
if (status & (I2C_ICR_ARLOCF | I2C_ICR_BERRCF)) return I2C_BUS_ERROR;
if (status & I2C_ISR_NACKF) return I2C_OPERATE_WRITE_NACK;
}
}

// Receive part
if (rcount)
{
u8_ptr = (uint8_t*)rcv;

I2C_Start_Direction_Adress_Size (Port, I2C_CR2_RD_WRN, addr, rcount);
if (Port->ISR & I2C_ISR_NACKF)
{
I2C_Stop(Port);
return I2C_OPERATE_NO_DEVICE;
}
u8_ptr = (uint8_t*)rcv;
while (!(Port->ISR & (I2C_ISR_TC | I2C_ISR_NACKF)) && (Port->ISR & I2C_ISR_BUSY))
{
if (Port->ISR & I2C_ISR_RXNE) *u8_ptr++ = Port->RXDR; // Receive data
}
}
status = Port->ISR;

I2C_Stop(Port);

if (status & (I2C_ICR_ARLOCF | I2C_ICR_BERRCF | I2C_ISR_NACKF)) // some errors
{
I2C_Stop(Port);
if (status & (I2C_ICR_ARLOCF | I2C_ICR_BERRCF)) return I2C_BUS_ERROR;
if (status & I2C_ISR_NACKF) return I2C_OPERATE_READ_NACK;
}

return I2C_OPERATE_OK;
}
Genadi Zawidowski
А в чем идея передачи tcount в I2C_Operate? Что-то он там только на ноль/не-ноль проверяется... Или так и задумано? Пока устройство не начнет в ответ что=то слать, передаем ему данные...
ps: давно пытаюсь сделать работающий модуль I2C для stm32f4xxx и для остальных. Пока не очень успешно - в работающих изделиях стоит программная реализация.
AHTOXA
Добавлю ссылочку на хорошую реализацию i2c на STM32 : тынц. Там всё подробно описано в комментариях.
toweroff
Цитата(Genadi Zawidowski @ Sep 24 2015, 10:01) *
А в чем идея передачи tcount в I2C_Operate? Что-то он там только на ноль/не-ноль проверяется... Или так и задумано? Пока устройство не начнет в ответ что=то слать, передаем ему данные...

ну здрасте!
Код
I2C_Start_Direction_Adress_Size(Port, 0, addr, tcount);

если 0, то просто проверится ACK от устройства на шине, а если не 0, так данные и будут вгоняться в соответствии с этим количеством (пока флаг TC не поднимется, а поднимется он после передачи tcount байт)
Genadi Zawidowski
"в соответствии с количеством" не получится - tcount только на ноль/не ноль проверяется вTransmit part... Или тут надежда на то, что контроллер отсчитает нужное количество сам?
toweroff
Цитата(Genadi Zawidowski @ Sep 25 2015, 08:57) *
"в соответствии с количеством" не получится - tcount только на ноль/не ноль проверяется вTransmit part...

проверяется. Именно для того, чтобы дать стартовую посылку

Цитата(Genadi Zawidowski @ Sep 25 2015, 08:57) *
Или тут надежда на то, что контроллер отсчитает нужное количество сам?

Нажмите для просмотра прикрепленного файла
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.