ATmega328PB双SPI总线(SPI0/SPI1)同时运行问题咨询
ATmega328PB双SPI总线同时工作的配置与解决方案
问题背景
在ATmega328PB控制器上尝试同时使用两路SPI总线:SPI0连接ENC28J60以太网芯片,SPI1连接TLE9879;基于Arduino框架,使用EtherCard以太网库和Infineon的TLE9879外部库。目前两路设备可分别在对应SPI总线上独立工作,但无法同时运行。已尝试为SPI1编写自定义传输函数、SPI0保留给以太网设备,仍未解决问题。
核心配置要点
ATmega328PB的SPI1是USART1复用的SPI模式,并非独立硬件SPI,这是关键的易忽略点,必须正确配置USART1为SPI模式才能正常工作:
USART1 SPI模式寄存器配置
手动设置UCSR1C寄存器启用SPI模式,同时配置对应引脚方向:// 配置USART1为SPI主机模式 UCSR1C = (1 << UMSEL11) | (1 << UMSEL10); UBRR1 = 0; // SPI模式下波特率寄存器无效,设为0 // 使能USART1的发送和接收 UCSR1B = (1 << TXEN1) | (1 << RXEN1); // 配置SPI1引脚方向:PB3=SCK1, PB1=MOSI1设为输出;PB2=MISO1设为输入 DDRB |= (1 << PB3) | (1 << PB1); DDRB &= ~(1 << PB2);严格的片选(CS)引脚管理
两路SPI设备的CS引脚必须单独控制,同一时间只能激活一个设备的CS:- SPI0的CS(通常为D10):访问ENC28J60时拉低,操作完成后立即拉高
- SPI1的CS(自定义引脚):访问TLE9879时拉低,操作完成后立即拉高
绝对不能同时拉低两个CS引脚,否则会导致总线数据冲突。
库兼容性适配
- EtherCard库默认使用SPI0(硬件SPI),无需修改,但要确保它不会意外修改SPI1的相关寄存器
- Infineon的TLE9879库如果默认调用SPI0的
SPI.transfer(),需要将其替换为自定义的SPI1传输函数,或修改库内的SPI操作逻辑为USART1 SPI模式
可行解决方案示例
1. 封装SPI1读写函数
// SPI1单字节传输(USART1 SPI模式) uint8_t spi1_transfer(uint8_t data) { while (!(UCSR1A & (1 << UDRE1))); // 等待发送缓冲区为空 UDR1 = data; while (!(UCSR1A & (1 << RXC1))); // 等待接收完成 return UDR1; } // SPI1多字节读写 void spi1_transfer_bytes(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len) { for (uint16_t i = 0; i < len; i++) { while (!(UCSR1A & (1 << UDRE1))); UDR1 = tx_buf ? tx_buf[i] : 0xFF; while (!(UCSR1A & (1 << RXC1))); if (rx_buf) rx_buf[i] = UDR1; } }
2. 修改TLE9879库的SPI操作
找到库中所有调用SPI.transfer()的代码,替换为上述spi1_transfer()函数,同时确保CS引脚的控制逻辑正确。
3. 优化初始化顺序
先初始化SPI0与ENC28J60,再初始化SPI1与TLE9879,避免初始化阶段的寄存器冲突:
#define TLE9879_CS 9 // 自定义SPI1的CS引脚 void setup() { // 初始化SPI0与ENC28J60 SPI.begin(); ether.begin(sizeof Ethernet::buffer, mymac, 10); // 10为SPI0的CS引脚 // 初始化SPI1 UCSR1C = (1 << UMSEL11) | (1 << UMSEL10); UBRR1 = 0; UCSR1B = (1 << TXEN1) | (1 << RXEN1); DDRB |= (1 << PB3) | (1 << PB1); DDRB &= ~(1 << PB2); pinMode(TLE9879_CS, OUTPUT); digitalWrite(TLE9879_CS, HIGH); // 初始化TLE9879 tle9879.init(); }
排查建议
- 核对SPI1引脚接线是否正确,确认SCK1、MOSI1、MISO1的对应关系
- 使用逻辑分析仪或示波器监测两路SPI总线的信号,排查是否存在冲突或异常波形
- 确认两个设备的SPI时钟极性(CPOL)和相位(CPHA)是否匹配各自的规格书,必要时在初始化阶段分别配置
内容的提问来源于stack exchange,提问作者Hemant Bhargava
相关产品推荐
相关产品推荐

