avr - 当接收时钟和从机选择作为输入时,尝试通过 SPI 作为从机发送 10 位数据(带缓冲模式)
问题描述
我正在尝试模拟来自 10 位 AEAT-6010 旋转编码器的数据,并将其发送到 ATtiny3217 上 SPI 协议的 MISO 引脚上。ATtiny 充当从机,接收 CLK 和 SS 信号作为输入,通过输出数据(编码器值)来响应。编码器按照SSI协议发送数据,如下图:
当尝试在 ATtiny 上发送 8 位 SPI 协议的 10 位时,就会出现问题。SPI 协议的主控芯片是 TMS320F2808 芯片,我从它接收 11 个时钟脉冲和 SS 信号。测得的信号和数据如下图所示:
这里我尝试发送的数据0b10
只是为了测试。我可以在 MISO 线上看到正确的数据,但信号中间有三个额外的 1。这是在 ATtinyBUFEN=1
的BUFWR=1
SPI 设置中,如下面的配置所示(没有缓冲模式,三个 1 出现在最后 3 位上,并且第一位(MSB)被读取为 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
}
我也尝试过按照这里的建议拆分 16 位数据,但问题仍然存在于 8 位数据中。希望这是足够的背景信息。我很感谢任何想法!
解决方案
在SPI_transmit
写入缓冲区后,您正在等待传输完成。之后,输入缓冲区被完全传输,现在是空的。
while(!(SPI0.INTFLAGS & (SPI_RXCIF_bm))); // waits until data is transmitted
RXCIF
当接收缓冲区中有数据时置位,即输出缓冲区的传输也完成。因此,当主机发送下一个字节时,输出缓冲区中还没有新数据要发送。可能 SPI 模块只是重复传输前一个字节。
因此,不要等待 RXCIF 标志,而是等待 DREIF 标志,当传输缓冲区为空并准备好接收下一个字节时,该标志将被设置。您可以忽略传入的数据,因为无论如何您都不会使用它
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
}
推荐阅读
- python - threading code.InteractiveInterpreter 并在执行命令时获取输出
- ffmpeg - ffmpeg推视频成功了,为什么一开始就出错了?
- java - 使用构造函数注入的组件测试问题
- python - 如何使用网页上的按钮调用类的方法 - Django -python
- amazon-web-services - VPN 站点到站点选项中的“内部隧道 IPv4 CIDR”是什么意思?
- reactjs - 我应该如何解决“预计在箭头函数结束时返回一个值。”?
- codeigniter - 在 codeigniter 3 中调用未定义的方法 CI_DB_mysqli_driver::prepare()?
- python - 从 app.py 到 html 的 for 循环返回未知
- javascript - react函数组件有return,但它返回void
- c# - 是否有像 dapper 这样的 .net 本机类/方法发出缓存类型属性来获取/设置值?