之前做过这部分工作,没有整理,现在回顾一下。
当FPGA 版本出来之后,怎么让AD9361 动起来 ,就是头等大事。当时十分在意,SPI是否通了?
- ENSM
AD9361收发器包括一个使能状态机(ENSM),允许对器件的当前状态进行实时控制。在正常运行过程中,器件可以置于多种不同状态,包括
• 待机—节能,频率合成器被禁用
• 休眠—待机,所有时钟/BB PLL被禁用
• TX—TX信号链被使能
• RX—RX信号链被使能
• FDD—TX和RX信号链被使能
• 报警—频率合成器被使能
上图中灰色状态不需要用户控制,经过设定的时间后进入下一个状态。TO_ALERT位在ENSM配置寄存器中,如果要切换到WAIT状态,需要在RX或TX状态下清除TO_ALERT位,这样从 Rx, Tx或FDD状态移出时,ENSM将转移到WAIT状态,如果TO_ALERT被置1,ENSM将转换到ALERT 状态。
ENSM有两种可能的控制方法:SPI控制和引脚控制。
1)通过SPI写寄存器将当前状态推进到下一个状态,可以异步控制ENSM。
2)使用ENABLE和TXNRX引脚实时控制当前状态
2.SPI控制
在SPI控制模式下,通过写SPI寄存器,从当前状态进入下一状态,从而实现对ENSM的异步控制。SPI控制被认为与DATA_CLK异步,因为SPI_CLK可能派生自一个不同的参考时钟,而且仍然能正常工作。当不需要对频率合成器进行实时控制时,推荐采用SPI控制ENSM法。只要BBIC能够精确执行SPI写操作,SPI控制就可以用于实时控制。
SPI接口
AD9361通过一个串行外设接口(SPI)与BBP通信。该接口可以配置为4线接口,带有专门的接收和发射端口,也可以配置为3线接口,带一个双向数据通信端口。该总线允许BBP通过一种简单地址数据串行总线协议,设置所有器件控制参数。
数据格式
分为3线模式和4线模式 控制字段由16bit组成,[15]为读写标志,高位读;[14:12]为读写的Byte数1~8Byte;[11:10]未使用;[9:0]为读写的起始字节地址;
前6位用于设置总线方向和需要传输的字节数。接下来的10位数据的写入地址。
/*
* SPI Comm Helpers
*/
#define AD_READ (0 << 15)
#define AD_WRITE (1 << 15)
#define AD_CNT(x) ((((x) - 1) & 0x7) << 12)
#define AD_ADDR(x) ((x) & 0x3FF)
写命令
最后8位是将被传输至指定寄存器地址(MSB至LSB)的数据。AD9361还支持LSB优先格式,允许命令以LSB至MSB格式写入。在该模式下,对于多字节写命令,寄存器地址将递增。
/**
* SPI register write.
* @param spi
* @param reg The register address.
* @param val The value of the register.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad9361_spi_write(struct spi_device *spi, uint32_t reg, uint32_t val)
{
uint8_t buf[3];
int32_t ret;
uint16_t cmd;
//uart_printf("ad9361_spi_write:reg[%d] = 0x%x\r\n",reg,val);
cmd = AD_WRITE | AD_CNT(1) | AD_ADDR(reg);
buf[0] = cmd >> 8;
buf[1] = cmd & 0xFF;
buf[2] = val;
ret = spi_write_then_read(spi, buf, 3, NULL, 0);
if (ret < 0) {
dev_err(&spi->dev, "Write Error %"PRId32, ret);
return ret;
}
return 0;
}
读命令
遵循相似的格式,区别在于,前16位在SPI_DI引脚上传输,最后8位从AD9361中读取,如果是4线模式,则在SPI_DO引脚上完成,如果是3线模式,则在SPI_DI引脚上完成。
/**
* SPI multiple bytes register read.
* @param spi
* @param reg The register address.
* @param rbuf The data buffer.
* @param num The number of bytes to read.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t ad9361_spi_readm(struct spi_device *spi, uint32_t reg,
uint8_t *rbuf, uint32_t num)
{
uint8_t buf[2];
int32_t ret;
uint16_t cmd;
if (num > MAX_MBYTE_SPI)
return -EINVAL;
cmd = AD_READ | AD_CNT(num) | AD_ADDR(reg);
buf[0] = cmd >> 8;
buf[1] = cmd & 0xFF;
ret = spi_write_then_read(spi, &buf[0], 2, rbuf, num);
if (ret < 0) {
dev_err(&spi->dev, "Read Error %"PRId32, ret);
return ret;
}
return 0;
}
SPI时序
3. SPI 模式
官方选的 SPI 模式2, 也就是 下降沿 为数据的开始,第一个跳变沿采样