接收时钟和从设备选择作为输入时,尝试通过SPI作为从设备发送10位数据(带缓冲模式)

时间:2019-07-08 09:50:55

标签: avr spi avr-gcc encoder attiny

我正在尝试模拟10位AEAT-6010旋转编码器中的数据,并将其通过ATtiny3217上SPI协议的MISO引脚发送出去。 ATtiny充当从设备,并接收CLK和SS信号作为输入,以通过输出数据(编码器值)进行响应。编码器遵循SSI协议发送数据,如下所示:

Encoder Timing Characteristics

尝试在ATtiny上通过8位SPI协议发送10位数据时出现问题。 SPI协议的主设备是TMS320F2808芯片,从中我接收11个时钟脉冲和SS信号。测量的信号和数据如下所示:

Oscilloscope measurements

这里我尝试发送的数据是0b10,仅用于测试。我可以在MISO线上看到正确的数据,但是信号中间还有三个1。如下面的配置所示,这是ATtiny的SPI设置中的BUFEN=1BUFWR=1(在没有缓冲模式的情况下,后3位是3,而在前3位是)读为1):

int8_t SPI_0_init()
{

    SPI0.CTRLA = 0 << SPI_CLK2X_bp    /* Enable Double Speed: disabled */
                 | 0 << SPI_DORD_bp   /* Data Order Setting: enabled */
                 | 1 << SPI_ENABLE_bp /* Enable Module: enabled */
                 | 0 << SPI_MASTER_bp /* SPI module in slave mode */
                 | SPI_PRESC_DIV4_gc; /* System Clock / 4 */

    SPI0.CTRLB = 1 << SPI_BUFEN_bp   /* Buffer Mode Enable: enabled */
                 | 1 << SPI_BUFWR_bp /* Buffer Write Mode: enabled */
                 | SPI_MODE_0_gc     /* SPI Mode 1 */
                 | 0 << SPI_SSD_bp;  /* Slave Select Disable: disabled */

    SPI0.INTCTRL = 0 << SPI_DREIE_bp    /* Data Register Empty Interrupt Enable: enabled */
                   | 1 << SPI_IE_bp     /* Interrupt Enable: enabled */
                   | 0 << SPI_RXCIE_bp  /* Receive Complete Interrupt Enable: disabled */
                   | 0 << SPI_SSIE_bp   /* Slave Select Trigger Interrupt Enable: disabled */
                   | 0 << SPI_TXCIE_bp; /* Transfer Complete Interrupt Enable: disabled */

    return 0;
}

我已经确认TMS320F2808的SPI模块和ATtiny的数据相同(在时钟下降沿读取)。关于SPI的缓冲区如何工作或SPI的中断,我是否缺少某些东西?我不确定在启用不同的中断时要在ISR中做什么(比清除标志还要多)。这是我的主要功能(ISR目前为空):

int main(void)
{
    /* Initializes MCU, drivers and middleware */
    atmel_start_init();

    sei(); // Enable global interrupts

    /* Replace with your application code */
    while (1) {

        SPI_transmit(enc_data_L);

}

SPI_transmit()如下:

void SPI_transmit(uint16_t enc_data)
{
    // Then start the transmission by assigning the data to the SPI data register
    SPI0.DATA = enc_data;
    //SPI0.DATA = enc_data_H;

    // Now wait for the data transmission to complete by periodically checking the SPI status register
    //the SPI_IF is the only interrupt flag with a function in non-buffered mode.
    while(!(SPI0.INTFLAGS & (SPI_RXCIF_bm)));
    SPI0.DATA; //Dummy read to clear flag
}

我也尝试按照建议的here拆分16位数据,但是对于8位数据也仍然存在问题。希望这是足够的背景信息。我感谢任何想法!

1 个答案:

答案 0 :(得分:0)

写入缓冲区后,SPI_transmit中的

您正在等待直到传输完成。此后,输入缓冲区已完全传输,现在为空。

  while(!(SPI0.INTFLAGS & (SPI_RXCIF_bm))); // waits until data is transmitted

RXCIF在接收缓冲区中有数据时设置,即输出缓冲区的传输也已完成。 因此,当主机发送下一个字节时,输出缓冲区中尚无新数据要发送。可能SPI模块只是重复发送前一个字节。

因此,当发送缓冲区为空并准备好下一个字节时,请等待设置的DREIF标志,而不是等待RXCIF标志。 您可以忽略传入的数据,因为您无论如何都不使用

void SPI_transmit(uint16_t enc_data)
{
    // Wait until buffer is ready to get the next data byte
    while(!(SPI0.INTFLAGS & (SPI_DREIF_bm))); 

    // Then start the transmission by assigning the data to the SPI data register
    SPI0.DATA = enc_data;

    // Don't care about read buffer
}