【问题标题】:Reading 22 bits via SPI [closed]通过 SPI 读取 22 位 [关闭]
【发布时间】:2015-11-03 21:54:21
【问题描述】:

我正在尝试使用 SPI 通信读取 ADC(ADS8320) 值。我正在为 ARM 和 SM470R1B1 控制器使用 IAR 嵌入式工作台。在数据表中,它说前 6 位是虚拟读取,接下来的 16 位是 actval 数据。我正在尝试读取 24 位并忽略前 6 位和后 2 位。当我尝试使用以下代码时,我得到了错误的值。

unsigned int readADC8320(void)  
{                 
   value = AD8320_16(0xFFFFFF);              // read registe    
   return value;
}

unsigned int AD8320_16(unsigned int value) 
{ 
unsigned int data; 
AD8320_CS_Status(0);
SW_Delay(DELAY_10US);
while(GIODOUTA&X2);
data = spi2(value >> 16);     //read high 8 bits
data = (data << 6)| spi2(value >> 8);   //read next 8 bits but 6+8 =14
data = (data << 8)| spi2(value >> 2);   //add last two bits only
SW_Delay(DELAY_10US);
AD8320_CS_Status(1);
return data; 
} 

unsigned char spi2(unsigned char data)
 {
// Write byte to SPI2DAT1 register
SPI2DAT1 = data;    

while(!(SPI2CTRL3 & 0x01)){}        // Wait for RxFlag to get set   
return (SPI2BUF & 0x000000FF);      // Read SPIBUF 
  }

谁能建议我哪里做错了。我的班次操作很差。

【问题讨论】:

  • 从描述您的系统开始。我们甚至不知道您使用的 CPU/MCU 是什么。
  • 你可能不擅长轮班操作,但你很不擅长提出问题,大概是测试和调试。当您使用调试器单步执行此代码时,作为“值”传递了什么以及如何将数据处理为“数据”?
  • 我的意思是,为什么只是将这些硬件驱动程序的东西转储给我们作为代码转储?我们不知道“价值”是理智的、颠倒的、正确的端序还是什么。据我们所知,您的 ADC 甚至没有通电,而您正在处理垃圾。
  • unsigned int 是 16 位还是 32 位?

标签: c embedded bit-shift spi adc


【解决方案1】:

您的代码看起来很不稳定。比如value有什么目的?

您链接到的数据表表明 22 个时钟周期就足够了(并且 24 个时钟周期是可以的),不需要额外的延迟,假设 SPI 时钟在限制范围内(我相信最多 2.4 MHz)。所以,我希望你的代码看起来更像

void AD8320_setup(void)
{
    /* TODO:
     *  - Set SPI2 clock frequency, if programmable (max. 2.4 MHz)
     *  - Set SPI2 transfer size, if programmable (8 bits per byte)
     *  - Set SPI2 to latch data on the falling edge of clock pulse
     *  - Set SPI2 to pull clock high when inactive
     *  - Set AD8320 chip select pin as an output
     *  - Set AD8320 chip select pin high (it is active low)
     *  - Ensure AD8320 is powered 
    */
}

uint16_t AD8320_16(void)
{
    uint16_t result;

    /* TODO: Set AD8320 chip select pin 0/LOW (to select it)
    */

    /* TODO: Clear SPI2 FIFO if it has one,
     *       so that we get actual wire data,
     *       not old cached data.
    */

    result = ((uint16_t)(spi2_read() & 3U)) << 14;
    result |= ((uint16_t)spi2_read()) << 6;
    result |= ((uint16_t)spi2_read()) >> 2;

    /* TODO: Set AD8320 chip select pin 1/HIGH (to deselect it)
    */

    return result;
}

spi2_read 的原型通常是unsigned char spi2_read(void);,但它可能是任何可以正确表示所有八位值的整数类型(0 到 255,包括 0 到 255)。在上面,我将结果(在使用二进制 AND 运算屏蔽掉任何不相关的位(如果有)之后)转换为 uint16_t,然后将其转移到结果中的正确位置,这样无论 spi2_read() 返回类型如何,我们可以用它来构造我们的 16 位值。

第一个 spi2_read() 读取前 8 位。我假设您的设备 SPI 总线首先发送和接收最高有效位;这意味着 6 个虚拟位是最高有效位,而 2 个最低有效位是结果的最高有效位。这就是为什么我们只保留第一个字节的两个最低有效位,并将其传输到剩下的 14 位——这样我们就可以将它们置于最高有效位置。

第二个spi2_read() 读取接下来的八位。这些是数据的第 13..6 位;这就是为什么我们将这个字节左移 6 位,并与现有数据进行 OR。

最后一个spi2_read() 读取接下来的八位。最后两位将被丢弃,因为只有前 6 位(最高有效位)包含我们感兴趣的其余数据。因此,我们将其向下移动 2 位,并与现有数据进行或运算。

准备 spi2 涉及字长(8 位)、数据速率(如果可编程)等。

AD8320 的片选只是一个通用输出引脚,它只是低电平有效。这就是为什么它在数据表中被描述为^CS/SHDN:低电平时选择芯片,高电平时关闭。

该芯片是微功率芯片,因此它需要的电流小于 2mA,因此您可以通过许多微控制器上的输出引脚为它供电。如果您要这样做,您还必须记住在_setup() 函数中将该引脚设置为输出和 1/high。

【讨论】:

  • 关于类型正确性的挑剔评论:要使强制转换产生任何效果,((uint16_t)(spi2_read() &amp; 3U)) &lt;&lt; 14; 应该是 ( (uint16_t)spi2_read() &amp; 3U) &lt;&lt; 14; 在任何隐式整数提升发生之前,对uint16_t 的强制转换应该在括号内。
  • @Lundin:哎呀!实际上,我在该段中的措辞是残酷的。我写道,我“将结果值”spi2_read())转换为uint16_t,但我的意思是我在掩码之后转换返回值,然后再转换。我会尝试修正这个措辞。我很高兴让编译器在这里选择处理位掩码的最佳方式,只要移位的值在 0 和 3 之间(包括 0 和 3),并且是 uint16_t 类型。毕竟,spi2_read() 必须能够返回 0 到 255(含)的无符号或有符号整数,并且只需要进行强制转换以确保我们可以构造 16 位结果。
猜你喜欢
  • 2012-01-25
  • 1970-01-01
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
相关资源
最近更新 更多