C 通过SPI读取22位

C 通过SPI读取22位,c,embedded,bit-shift,spi,adc,C,Embedded,Bit Shift,Spi,Adc,我正在尝试使用SPI通信读取ADC值。我正在为ARM和SM470R1B1控制器使用IAR嵌入式工作台。在数据表中,它表示前6位为伪读,后16位为actval数据。我尝试读取24位,忽略前6位和最后2位。当我尝试使用下面的代码时,我得到了错误的值 unsigned int readADC8320(void) { value = AD8320_16(0xFFFFFF); // read registe return

我正在尝试使用SPI通信读取ADC值。我正在为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 
  }

谁能告诉我哪里做错了。我的轮班操作很差。

你的代码看起来不可靠。例如,价值有什么目的

您链接到的数据表表明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的原型通常是无符号字符spi2_readvoid;,但它可能是任何整数类型,可以正确地表示所有8位值0到255(包括0到255)。在上面,我将结果(在用二进制AND运算屏蔽掉任何不相关的位(如果有)后)转换到uint16_t,然后将其转换到结果中的正确位置,这样,无论spi2_读取返回类型如何,我们都可以使用它来构造16位值

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

第二次spi2_读取后八位。这些是数据的位13..6;这就是为什么我们将这个字节左移6位,或者使用现有数据

最后一次spi2_读取后八位。最后两位将被丢弃,因为只有前最重要的6位包含我们感兴趣的其余数据。因此,我们将其向下移动2个位置,或者使用现有数据

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

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


该芯片是一个微功耗芯片,所以它需要不到2毫安的电流,所以你可以想象,可以从许多微控制器的输出引脚为它供电。如果要这样做,您还必须记住将该引脚设置为输出,并在设置功能中设置为1/high。

从描述您的系统开始。我们甚至不知道您使用的CPU/MCU是什么。您可能对轮班操作很差,但您在提问、测试和调试方面非常差。当你用调试器处理这段代码时,什么是作为“值”传递的,数据是如何被处理成“数据”的?我的意思是,为什么只把这些硬件驱动程序的东西作为代码转储放在我们身上呢?我们不知道“价值”是健全的、颠倒的、正确的终结性还是什么。据我们所知,您的ADC甚至没有通电,您正在处理垃圾。unsigned int是16位还是32位?关于类型正确性的挑剔评论:为了使强制转换产生任何效果,uint16_tspi2_read&3U@Lundin:Oops!事实上,我在那一段中的措词很糟糕。我写道,我将spi2_read的结果值强制转换为uint16_t,但我的意思是,在屏蔽之后,在移位之前,我强制转换返回值。我会试着修改一下措辞。我很乐意让编译器在这里选择处理位屏蔽的最佳方式,只要位移位的值介于0和3之间(含0和3),并且是uint16\t类型。毕竟,spi2_read必须能够返回0到255(包括0到255)的无符号或有符号整数,而强制转换只需要确保我们能够构造16位结果。