arm 实现mdio 读写 88X5113 寄存器
88X5113 芯片说明
该芯片和平常的phy芯片不同, 以下为芯片采用 MDIO 接口实现读写寄存器的说明
配置说明
- 寄存器分为基地址和扩展地址, 每次读写扩展地址的数据, 需要先将扩展地址 使用
op=00
写进基地址中, 然后在进行读写该基地址, 就会将所需的扩展地址的数据读出来 - 我调试的芯片有个问题: 就是mdio读数据的时候,时钟应该时32个和写进去的一样,但实际调试过程中在
TA
转向的时候, 会少一个时钟周期,导致读出来的数据总是末尾多一个1
代码实现
IIC_88X5113.h
#ifndef __IIC_88X5113_h__
#define __IIC_88X5113_h__
#include "sys.h"
#include "stm32f10x_gpio.h"
#include "delay.h"
#define RT_OK 0
#define MODEL_WIRE_ADDR 0x00
#define MODEL_WIRE_DATA 0x01
#define MODEL_READ_DATA 0x02
#define MODEL_READ_INCR 0x03
#endif
IIC_88X5113.c
#include "IIC_88X5113.h"
#define MCU_4T4R_1_SDA_MDIO GPIO_Pin_0
#define MCU_4T4R_1_SCL_MDC GPIO_Pin_1
// #define SET_INPUT {GPIOA->CRL &= ~(0xf);GPIOA->CRL |= (0xa);}
#define IIC_DEBUG(...) printf(__VA_ARGS__)
#define WRITE_MDC(VAL) GPIO_WriteBit(GPIOA, MCU_4T4R_1_SCL_MDC, VAL)
#define WRITE_MDIO(VAL) GPIO_WriteBit(GPIOA, MCU_4T4R_1_SDA_MDIO, VAL)
#define READ_MDIO() GPIO_ReadInputDataBit(GPIOA, MCU_4T4R_1_SDA_MDIO)
// #define READ_MDIO() GPIO_ReadOutputDataBit(GPIOA, MCU_4T4R_1_SDA_MDIO);
#define HIG_SET 1
#define LOW_SET 0
void IIC_GPIO_INIT() {
GPIO_InitTypeDef GPIO_InitStructure;
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟
GPIO_InitStructure.GPIO_Pin = MCU_4T4R_1_SCL_MDC;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = MCU_4T4R_1_SDA_MDIO;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_WriteBit(GPIOA, MCU_4T4R_1_SCL_MDC, 0);
GPIO_WriteBit(GPIOA, MCU_4T4R_1_SDA_MDIO, 0);
// IIC_DEBUG("\r\n#INFO: init MDIO GPIO is PA0");
// IIC_DEBUG("\r\n#INFO: init MDC GPIO is PA1");
}
void SET_MDIO_ZZZ(){
GPIOA->CRL = (GPIOA->CRL & 0xFFFFFFF0) | 0x00000008;
// GPIO_InitTypeDef GPIO_InitStructure;
// GPIO_InitStructure.GPIO_Pin = MCU_4T4R_1_SDA_MDIO;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_Init(GPIOA, &GPIO_InitStructure);
// IIC_DEBUG("\r\n#INFO: set MDIO ZZZ");
}
void SET_MDIO_AFP(){
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = MCU_4T4R_1_SDA_MDIO;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_WriteBit(GPIOA, MCU_4T4R_1_SDA_MDIO, 0);
// IIC_DEBUG("\r\n#INFO: set MDIO AF_PP");
}
void MDC_CLOCK(u32 delay_time, u16 offset_time) {
delay_us(delay_time - offset_time);
WRITE_MDC(HIG_SET);
delay_us(delay_time);
WRITE_MDC(LOW_SET);
delay_us(offset_time);
}
void IIC_WIRE(u32 cmd, u32 delay_time, u32 offset_time) {
int count = 0;
int cnt = 0;
u8 bit = 0;
SET_MDIO_AFP();
while (1)
{
MDC_CLOCK(delay_time, offset_time);
count++;
if(count > 31) {
bit = (cmd>>(31-cnt)) & 0x01;
if(bit) {
WRITE_MDIO(1);
} else {
WRITE_MDIO(0);
}
// IIC_DEBUG("\r\n#INFO cnt is %d, binary: %d", cnt, bit);
cnt++;
if(cnt > 31) {
break;
};
} else {
WRITE_MDIO(HIG_SET); //持续拉高
// IIC_DEBUG("\r\n 测试循环");
}
}
MDC_CLOCK(delay_time, offset_time);
SET_MDIO_AFP();
}
u16 IIC_READ(u32 cmd, u32 delay_time, u32 offset_time) {
int count = 0;
int cnt = 0;
unsigned char bit = 0;
unsigned short res = 0;
unsigned short temp = 0;
SET_MDIO_AFP();
while (1)
{
MDC_CLOCK(delay_time, offset_time);
count++;
if(count > 31) {
bit = (cmd>>(31-cnt)) & 0x01;
if(bit) {
WRITE_MDIO(1);
} else {
WRITE_MDIO(0);
}
// IIC_DEBUG("\r\n#INFO: cnt is %d, binary: %d", cnt, bit);
cnt++;
if(cnt > 13) break;
} else {
WRITE_MDIO(HIG_SET); //持续拉高
// IIC_DEBUG("\r\n 测试循环");
}
}
MDC_CLOCK(delay_time, offset_time);
SET_MDIO_ZZZ();
MDC_CLOCK(delay_time, offset_time);
cnt = 0;
bit = 0;
while (1) {
MDC_CLOCK(delay_time, offset_time);
cnt++;
if(cnt <= 16) {
bit = READ_MDIO();
temp = ((bit & 0x0001) << (16 - cnt));
res = res | temp;
// IIC_DEBUG("\r\n#INFO: cnt is %d, read bit is %d, temp is %04x, res is 0x%04x, res | temp: %04x", cnt, bit, temp, res, res | temp);
} else {
break;
}
}
// MDC_CLOCK(delay_time, offset_time);
SET_MDIO_AFP();
return res;
}
int _88X5113_OPER(u32 delay_time, u32 offset_time, u8 opr_addr, u8 model, u16 cdata) {
u8 phy_addr = 0x08; // 0b00001000
u16 res = 0;
int cmd = 0x00000000;
u16 cdata_temp = cdata;
u8 cnt = 0;
u8 bit = 0;
// if(model == MODEL_WIRE_DATA) {
// cdata = 0x0000;
// while (cnt++ < 16) {
// bit = (cdata_temp >> (16 - cnt)) & 0x0001;
// cdata = cdata | (bit << cnt - 1);
// // IIC_DEBUG("\r\n==> cnt: %d, bit: %0x cdata: %4x", cnt, bit, cdata);
// }
// }
cmd |= ((model | 0x00000000) << (28)); //设置 OP|ST
cmd |= ((phy_addr | 0x00000000) << (20)); //设置 phyaddr
cmd |= ((opr_addr | 0x00000000) << (18)); //设置 DEVADR
cmd |= ((0x02 | 0x00000000) << (16)); //设置 TA
cmd |= ((cdata | 0x00000000) << (0 )); //设置 数据位
// IIC_DEBUG("\r\nOPER_CMD is 0x%08x ", cmd);
if(model == MODEL_READ_DATA || model == MODEL_READ_INCR) {
res = IIC_READ(cmd, delay_time, offset_time);
}
if(model == MODEL_WIRE_ADDR || model == MODEL_WIRE_DATA) {
IIC_WIRE(cmd, delay_time, offset_time);
}
return res;
}
// u32 delay_time = 500; //半个时钟周期的时长,单位us
// u32 offset_time = 200; //时钟延时,必须小于 delay_time
u32 delay_time = 10; //半个时钟周期的时长,单位us
u32 offset_time = 2; //时钟延时,必须小于 delay_time
#define OPER_INTERVAL 10
u16 read_REG(u8 opr_addr, u16 opr_regi) {
u16 res = 0x0000;
res = _88X5113_OPER(delay_time, offset_time, opr_addr, MODEL_WIRE_ADDR, opr_regi); //00 00 00001 00011 10, 0x008E_0010, 00 00 10000 00011 10, 0x080E_0010
delay_ms(OPER_INTERVAL);
res = _88X5113_OPER(delay_time, offset_time, opr_addr, MODEL_READ_INCR, 0); //00 1
delay_ms(OPER_INTERVAL);
IIC_DEBUG("\r\n#INFO: -read_REG- %2d.%04x=0x%04x", opr_addr, opr_regi, res);
return res;
}
void wire_REG(u8 opr_addr, u16 opr_regi, u16 conf_dat) {
_88X5113_OPER(delay_time, offset_time, opr_addr, MODEL_WIRE_ADDR, opr_regi); //00 00 00001 00011 10, 0x008E_0010, 00 00 10000 00011 10, 0x080E_0010
delay_ms(OPER_INTERVAL);
_88X5113_OPER(delay_time, offset_time, opr_addr, MODEL_WIRE_DATA, conf_dat); //00 01 00001 00011 10, 0x108E_0010, 00 01 10000 00011 10, 0x180E_0010
delay_ms(OPER_INTERVAL);
}
void IIC_88X5113() {
u16 res = 0;
u8 opr_addr = 0x07; //操作寄存器 基地址
u16 opr_regi = 0x0000; //操作寄存器地址
u16 conf_dat = 0x0010; //需要写入的数据
// IIC_DEBUG("1");
// delay_ms(2000); //延迟
// IIC_DEBUG("2");
wire_REG(31, 0xF404,0x4000); //15=1 软复位, 14=1 硬复位,, 先硬复位
delay_ms(5000); //延迟
IIC_DEBUG("\r\n============== IIC_GPIO_INIT =================");
IIC_GPIO_INIT();
// wire_REG(0x07, 0x0000, conf_dat);
// wire_REG(7, 0x0000, 0x1000); //自动协商 line
// wire_REG(7, 0x1000, 0x1000); //自动协商 host
// wire_REG(3, 0xF000, 0x0025); //line, SR4_P40LN, 31.F00n 1XXX_XXX0_0010_0101
wire_REG(3, 0xF000, 0x0035); //line, CR4_P40CN, 31.F00n 1XXX_XX00_0011_0101
wire_REG(4, 0xF000, 0x0235); //host, KR4_P40KN, 31.F00n 1XXX_XX10_0011_0101
wire_REG(31, 0xF437, 0x8000); //LED1 host side
wire_REG(31, 0xF438, 0x1160); //LED1 0001_0110_0110_0000
wire_REG(31, 0xF439, 0x8000); //LED2 host side
wire_REG(31, 0xF43A, 0x1660); //LED2 0001_0110_0110_0000
wire_REG(31, 0xF43B, 0x8000); //LED3 line side
wire_REG(31, 0xF43C, 0x1660); //LED3 0000_0110_0110_0000
wire_REG(31, 0xF43D, 0x8000); //LED4 line side
wire_REG(31, 0xF43E, 0x1660); //LED4 0000_0110_0110_0000
// res = read_REG(3, 0x1000); //数据复位
// wire_REG(3, 0x1000, (0x8000 | res)); //line 复位
// res = read_REG(4, 0x1000);
// wire_REG(4, 0x1000, (0x8000 | res)); //host 复位
// res = read_REG(3, 0x3000);
// wire_REG(3, 0x3000, (0x1040 | res)); //line
// res = read_REG(3, 0xB000);
// wire_REG(3, 0xB000, (0x2000 | res)); //host 复位
// wire_REG(31, 0xF404,0x8000); //15=1 软复位, 14=1 硬复位, 设置之后软复位
delay_ms(1000);
while(1) {
IIC_DEBUG("\r\n=========================================>");
read_REG(3, 0x9003); //40G/50G link status 11-10, Local Fault Transmitted, Local Fault Received
read_REG(4, 0x9003); //40G/50G link status 11-10, Local Fault Transmitted, Local Fault Received
read_REG(3, 0xF000);
read_REG(4, 0xF000);
read_REG(3, 0x3004);
read_REG(7, 0x0000); //自动协商
read_REG(7, 0x1000); //自动协商
//L0 rv_cnt
// read_REG(3, 0xF104);
// read_REG(3, 0xF105);
// read_REG(3, 0xF106);
//h0 rv_cnt
// read_REG(4, 0xF104);
// read_REG(4, 0xF105);
// read_REG(4, 0xF106);
// read_REG(3, 0x1000);
// read_REG(4, 0x1000); //284c 0010_1000_0100_1101
delay_ms(1000);
//led1 灯闪烁
// delay_ms(500);
// wire_REG(0x1f, 0xF439, 0x8000);
// delay_ms(500);
// wire_REG(0x1f, 0xF439, 0x0000);
}
}
本文来自博客园踩坑狭,作者:韩若明瞳,转载请注明原文链接:https://www.cnblogs.com/han-guang-xue/p/16876905.html