1. использую Opencores I2C Master.
2. в соответствии с даташитом на АЦП я описал выводы:

QuartusII:
Код
...
output scl_pad_io;
inout sda_pad_io;
wire scl_pad_io;
wire sda_pad_io;
...
.scl_pad_io_to_and_from_the_opencores_i2c_master_0(scl_pad_io),
.sda_pad_io_to_and_from_the_opencores_i2c_master_0(sda_pad_io)
...
3. взял готовую программную реализацию:output scl_pad_io;
inout sda_pad_io;
wire scl_pad_io;
wire sda_pad_io;
...
.scl_pad_io_to_and_from_the_opencores_i2c_master_0(scl_pad_io),
.sda_pad_io_to_and_from_the_opencores_i2c_master_0(sda_pad_io)
...
Код
#include <io.h>
#include "system.h"
// Overall status and control
#define IOWR_I2C_PRERLO(port,data) IOWR(port, 0, data)
#define IOWR_I2C_PRERHI(port,data) IOWR(port, 1, data)
#define IOWR_I2C_CTR(port,data) IOWR(port, 2, data)
#define IOWR_I2C_TXR(port,data) IOWR(port, 3, data)
#define IOWR_I2C_CR(port,data) IOWR(port, 4, data)
#define IORD_I2C_PRERLO IORD(port, 0)
#define IORD_I2C_PRERHI IORD(port, 1)
#define IORD_I2C_CTR IORD(port, 2)
#define IORD_I2C_RXR IORD(port, 3)
#define IORD_I2C_SR IORD(port, 4)
#define I2C_CR_STA 0x80
#define I2C_CR_STO 0x40
#define I2C_CR_RD 0x20
#define I2C_CR_WR 0x10
#define I2C_CR_ACK 0x08
#define I2C_CR_IACK 0x01
#define I2C_SR_TIP 0x02
#define I2C_SR_RXNACK 0x80
#define DELAY_TIME 35
void i2c_write(long port, unsigned char address, unsigned char reg, unsigned char data);
unsigned char i2c_read(long port, unsigned char address, unsigned char reg);
void init_i2c(long port,unsigned char address);
void i2c_wait_tip(long port);
void i2c_wait_rxnack(long port);
int main() {
init_i2c(OPENCORES_I2C_MASTER_0_BASE,0xBA>>1);
unsigned char data = i2c_read(OPENCORES_I2C_MASTER_0_BASE,0xBA>>1,0x0B);
printf("reg: 0x%X",data);
return 0;
}
void i2c_write(long port, unsigned char address, unsigned char reg, unsigned char data) {
i2c_wait_tip(port);
// write address
IOWR_I2C_TXR(port, address<<1);
IOWR_I2C_CR(port, I2C_CR_STA | I2C_CR_WR | I2C_CR_ACK);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// write register address
IOWR_I2C_TXR(port, reg);
IOWR_I2C_CR(port, I2C_CR_WR | I2C_CR_ACK);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// write data
IOWR_I2C_TXR(port, data);
IOWR_I2C_CR(port, I2C_CR_WR | I2C_CR_STO | I2C_CR_IACK);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
}
unsigned char i2c_read(long port, unsigned char address, unsigned char reg) {
i2c_wait_tip(port);
// write address
IOWR_I2C_TXR(port, address<<1);
IOWR_I2C_CR(port, I2C_CR_STA | I2C_CR_WR);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// write register address
IOWR_I2C_TXR(port, reg);
IOWR_I2C_CR(port, I2C_CR_WR);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// write address for reading
IOWR_I2C_TXR(port, (address<<1) | 1);
IOWR_I2C_CR(port, I2C_CR_STA | I2C_CR_WR);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// read data
IOWR_I2C_CR(port, I2C_CR_RD | I2C_CR_ACK | I2C_CR_STO);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
return IORD_I2C_RXR;
}
void init_i2c(long port,unsigned char address) {
// Setup prescaler
int prescale = 200000000/(5*100000)-1;
IOWR_I2C_PRERLO(port, prescale & 0xff);
IOWR_I2C_PRERHI(port, (prescale & 0xff00)>>8);
// Enable core
IOWR_I2C_CTR(port, 0x80);
// write init values
i2c_write(port,address,0xE8,0x02);
i2c_write(port,address,0xE9,0x00);
i2c_write(port,address,0xEA,0x80);
i2c_write(port,address,0xE0,0x01);
i2c_write(port,address,0xE8,0x60);
i2c_write(port,address,0xE9,0x00);
i2c_write(port,address,0xEA,0xB0);
i2c_write(port,address,0xE0,0x01);
i2c_write(port,address,0xE0,0x00);
i2c_write(port,address,0x03,0x01);
i2c_write(port,address,0x03,0x00);
}
void i2c_wait_tip(long port) {
int cnt=20*DELAY_TIME;
unsigned char status;
status = IORD_I2C_SR;
for(; cnt != 0; cnt--) {
if(status & I2C_SR_TIP) status = IORD_I2C_SR;
else break;
if(cnt == 1) {
printf("write slave address TIP fail\n");
return -1;
}
}
return 0;
}
void i2c_wait_rxnack(long port) {
unsigned char cnt=20*DELAY_TIME,status;
status = IORD_I2C_SR;
for(; cnt != 0; cnt--) {
if(status & I2C_SR_RXNACK) status = IORD_I2C_SR;
else break;
if(cnt == 1) {
printf("RXNACK fail\n");
return -1;
}
}
return 0;
}
4. пытаюсь связаться с одним из декодеров TVP5146 по адресу 0xBA и прочитать регистр 0x0B. В ответ всегда приходит значение 0x00. При этом проверка на флаги TIP и RXNACK удачна (но даже и в том случае, когда я обращаюсь по неверному адресу устройства). Т.е. связь с ядром I2C видимо есть, а с АЦП - нет.#include "system.h"
// Overall status and control
#define IOWR_I2C_PRERLO(port,data) IOWR(port, 0, data)
#define IOWR_I2C_PRERHI(port,data) IOWR(port, 1, data)
#define IOWR_I2C_CTR(port,data) IOWR(port, 2, data)
#define IOWR_I2C_TXR(port,data) IOWR(port, 3, data)
#define IOWR_I2C_CR(port,data) IOWR(port, 4, data)
#define IORD_I2C_PRERLO IORD(port, 0)
#define IORD_I2C_PRERHI IORD(port, 1)
#define IORD_I2C_CTR IORD(port, 2)
#define IORD_I2C_RXR IORD(port, 3)
#define IORD_I2C_SR IORD(port, 4)
#define I2C_CR_STA 0x80
#define I2C_CR_STO 0x40
#define I2C_CR_RD 0x20
#define I2C_CR_WR 0x10
#define I2C_CR_ACK 0x08
#define I2C_CR_IACK 0x01
#define I2C_SR_TIP 0x02
#define I2C_SR_RXNACK 0x80
#define DELAY_TIME 35
void i2c_write(long port, unsigned char address, unsigned char reg, unsigned char data);
unsigned char i2c_read(long port, unsigned char address, unsigned char reg);
void init_i2c(long port,unsigned char address);
void i2c_wait_tip(long port);
void i2c_wait_rxnack(long port);
int main() {
init_i2c(OPENCORES_I2C_MASTER_0_BASE,0xBA>>1);
unsigned char data = i2c_read(OPENCORES_I2C_MASTER_0_BASE,0xBA>>1,0x0B);
printf("reg: 0x%X",data);
return 0;
}
void i2c_write(long port, unsigned char address, unsigned char reg, unsigned char data) {
i2c_wait_tip(port);
// write address
IOWR_I2C_TXR(port, address<<1);
IOWR_I2C_CR(port, I2C_CR_STA | I2C_CR_WR | I2C_CR_ACK);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// write register address
IOWR_I2C_TXR(port, reg);
IOWR_I2C_CR(port, I2C_CR_WR | I2C_CR_ACK);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// write data
IOWR_I2C_TXR(port, data);
IOWR_I2C_CR(port, I2C_CR_WR | I2C_CR_STO | I2C_CR_IACK);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
}
unsigned char i2c_read(long port, unsigned char address, unsigned char reg) {
i2c_wait_tip(port);
// write address
IOWR_I2C_TXR(port, address<<1);
IOWR_I2C_CR(port, I2C_CR_STA | I2C_CR_WR);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// write register address
IOWR_I2C_TXR(port, reg);
IOWR_I2C_CR(port, I2C_CR_WR);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// write address for reading
IOWR_I2C_TXR(port, (address<<1) | 1);
IOWR_I2C_CR(port, I2C_CR_STA | I2C_CR_WR);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
// read data
IOWR_I2C_CR(port, I2C_CR_RD | I2C_CR_ACK | I2C_CR_STO);
i2c_wait_tip(port);
i2c_wait_rxnack(port);
return IORD_I2C_RXR;
}
void init_i2c(long port,unsigned char address) {
// Setup prescaler
int prescale = 200000000/(5*100000)-1;
IOWR_I2C_PRERLO(port, prescale & 0xff);
IOWR_I2C_PRERHI(port, (prescale & 0xff00)>>8);
// Enable core
IOWR_I2C_CTR(port, 0x80);
// write init values
i2c_write(port,address,0xE8,0x02);
i2c_write(port,address,0xE9,0x00);
i2c_write(port,address,0xEA,0x80);
i2c_write(port,address,0xE0,0x01);
i2c_write(port,address,0xE8,0x60);
i2c_write(port,address,0xE9,0x00);
i2c_write(port,address,0xEA,0xB0);
i2c_write(port,address,0xE0,0x01);
i2c_write(port,address,0xE0,0x00);
i2c_write(port,address,0x03,0x01);
i2c_write(port,address,0x03,0x00);
}
void i2c_wait_tip(long port) {
int cnt=20*DELAY_TIME;
unsigned char status;
status = IORD_I2C_SR;
for(; cnt != 0; cnt--) {
if(status & I2C_SR_TIP) status = IORD_I2C_SR;
else break;
if(cnt == 1) {
printf("write slave address TIP fail\n");
return -1;
}
}
return 0;
}
void i2c_wait_rxnack(long port) {
unsigned char cnt=20*DELAY_TIME,status;
status = IORD_I2C_SR;
for(; cnt != 0; cnt--) {
if(status & I2C_SR_RXNACK) status = IORD_I2C_SR;
else break;
if(cnt == 1) {
printf("RXNACK fail\n");
return -1;
}
}
return 0;
}
В связи с этим несколько вопросов:
1. достаточно ли для инициализации и дальнейшего общения с декодером использовать только линии SCL и SDA, которые предлагает Opencores I2C Master (нужны ли RESETB и I2CA) ?
2. насколько я понял, АЦП не имеет интерфейса WISHBONE (по крайней мере об этом нигде не написано). Возможно ли тогда вообще использовать в данном случае Opencores I2C Master? (как, например, расчитать значение делителя частоты?)
Спасибо.