本文主要测试了驱动的以太网, spi , pwm 和can , 总结的问题代码如下
M4内核 1m flash 512k ram , 288Mhz 主频, 只要28元的国产芯片, 封装可替换STM32 f4系列型号
以太网
以太网测试下来主要体现在三个地方有问题
1 压力测试下, 出现再也无法使用网络的情况
原因为, 中断服务函数太臃肿, 注释掉之后, 性能稳定
代码如下 注释掉用不到的中断判断
void EMAC_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
/* clear received it */
// if(emac_dma_flag_get(EMAC_DMA_NIS_FLAG) != RESET)
// {
// emac_dma_flag_clear(EMAC_DMA_NIS_FLAG);
// }
// if(emac_dma_flag_get(EMAC_DMA_AIS_FLAG) != RESET)
// {
// emac_dma_flag_clear(EMAC_DMA_AIS_FLAG);
// }
// if(emac_dma_flag_get(EMAC_DMA_OVF_FLAG) != RESET)
// {
// emac_dma_flag_clear(EMAC_DMA_OVF_FLAG);
// }
// if(emac_dma_flag_get(EMAC_DMA_RBU_FLAG) != RESET)
// {
// emac_dma_flag_clear(EMAC_DMA_RBU_FLAG);
// }
// if(emac_dma_flag_get(EMAC_DMA_FBEI_FLAG) != RESET)
// {
// emac_dma_flag_clear(EMAC_DMA_FBEI_FLAG);
// rt_kprintf("emac fatal errrn");
// }
/* packet receiption */
if (emac_dma_flag_get(EMAC_DMA_RI_FLAG) == SET)
{
/* a frame has been received */
eth_device_ready(&(at32_emac_device.parent));
emac_dma_flag_clear(EMAC_DMA_RI_FLAG);
}
/* packet transmission */
if (emac_dma_flag_get(EMAC_DMA_TI_FLAG) == SET)
{
if (tx_is_waiting == RT_TRUE)
{
tx_is_waiting = RT_FALSE;
rt_sem_release(&tx_wait);
}
emac_dma_flag_clear(EMAC_DMA_TI_FLAG);
}
emac_dma_flag_clear(EMAC_DMA_NIS_FLAG);
emac_dma_flag_clear(EMAC_DMA_TI_FLAG);
emac_dma_flag_clear(EMAC_DMA_RI_FLAG);
// EMAC->ctrl_bit.re = 1;
// nvic_irq_enable(EMAC_IRQn, 0x01, 0); // lzf 0x7-0x1
/* leave interrupt */
rt_interrupt_leave();
}
2 iperf以客户端模式下运行, 会触发断言错误
原因为, 发送信号量未初始化,导致 在初始化函数内, 添加信号量初始化即可
// rt_hw_at32_emac_init函数中
rt_sem_init(&tx_wait, "tx_wait", 0, RT_IPC_FLAG_FIFO);
3 未查网线的情况下, 无法继续运行到main 函数
原因为, 初始化函数中, 有死等phy 连接状态 解决方案, 直接注释掉, 实测依然能够正常连接到以太网, 死等意义不大, 暂未发现其他问题
static error_status emac_speed_config(emac_auto_negotiation_type nego, emac_duplex_type mode, emac_speed_type speed)
{
uint16_t data = 0;
uint32_t timeout = 0;
if(nego == EMAC_AUTO_NEGOTIATION_ON)
{
// do // 不进行连接判断, 在未连接的状态下配置剩余参数
// {
// timeout++;
// if(emac_phy_register_read(phy_addr, PHY_STATUS_REG, &data) == ERROR)
// {
// return ERROR;
// }
// } while(!(data & PHY_LINKED_STATUS_BIT) && (timeout < PHY_TIMEOUT)); // 在这里卡死
if(timeout == PHY_TIMEOUT)
{
return ERROR;
}
timeout = 0;
if(emac_phy_register_write(phy_addr, PHY_CONTROL_REG, PHY_AUTO_NEGOTIATION_BIT) == ERROR)
{
return ERROR;
}
// do // 都没连接网线, 直接跳过判断
// {
// timeout++;
// if(emac_phy_register_read(phy_addr, PHY_STATUS_REG, &data) == ERROR)
// {
// return ERROR;
// }
// } while(!(data & PHY_NEGO_COMPLETE_BIT) && (timeout < PHY_TIMEOUT));
if(timeout == PHY_TIMEOUT)
{
return ERROR;
}
if(emac_phy_register_read(phy_addr, PHY_SPECIFIED_CS_REG, &data) == ERROR)
{
return ERROR;
}
.......................................................
后面略
4 未适配lan8720
适配方法如下 1 在drv_emac.h 添加如下代码
#if defined (PHY_USING_LAN8720A)
/////////////////////////////////////////////
#define PHY_CONTROL_REG (0x00) /*!< basic mode control register 1 等价于 basic_control_reg*/
#define PHY_STATUS_REG (0x01) /*!< basic mode status register 1 等价于 PHY_BASIC_STATUS_REG*/
#define PHY_SPECIFIED_CS_REG (0x1FU) /*!< phy status register 22 读取这个寄存器, 获取连接状态*/
/* phy control register */
#define PHY_AUTO_NEGOTIATION_BIT (0x1000) /*!< enable auto negotiation 基础控制寄存器上, 写了这个寄存器位, 就代表使能自动协商了 */
// #define PHY_LOOPBACK_BIT (0x4000) /*!< enable loopback */
#define PHY_RESET_BIT (0x8000) /*!< reset phy 软件复位的寄存器位, 对的*/
/* phy status register */
#define PHY_LINKED_STATUS_BIT (0x0004) /*!< link status 基础状态寄存器读取来的, 0x4*/
#define PHY_NEGO_COMPLETE_BIT (0x0020) /*!< auto negotiation complete 基础状态寄存器读取来的, 没问题 */
#define PHY_DUPLEX_MODE (1<<4) //(0x0004) /*!< x---- full duplex mode 特别状态寄存器, 2位 10MBbit 3 位 100m , 4位表示半全双工 */
#define PHY_SPEED_MODE (1<<2) //)(0x0002) /*!< -10 mbps 标识位 51页 */
/* the phy interrupt source flag register. */
#define PHY_INTERRUPT_FLAG_REG 0x1DU /* 数据手册上为 interrupt souce register 第42页 */
// #define PHY_LINK_CHANGE_FLAG (1<<13) 8720 没有用到这玩意
/* the phy interrupt control register. */
//#define PHY_INTERRUPT_CTRL_REG 0x11U 没有这玩意, 只有dp83848 有
// #define PHY_INTERRUPT_EN ((1<<0)|(1<<1))//没有这玩意, 只有dp83848 有
/* the phy interrupt mask register. */
#define PHY_INTERRUPT_MASK_REG 0x1EU //
#endif
2 drv_emac.c 中 emac_speed_config, 添加如下代码
#ifdef PHY_USING_LAN8720A
//8720
emac_fast_speed_set(EMAC_SPEED_100MBPS);
emac_duplex_mode_set(EMAC_FULL_DUPLEX);// 没有这两行, 获取不了ip 地址
#endif
spi 测试
spi 使用未遇到问题,可以完美的并入到rtt 的设备驱动框架,缺点就是不支持dma 使用rt_spi_attach 需要注意细微的区别
can 测试
can 驱动有点问题, 主要在id 上无法正确读到拓展帧, 修改如下
static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
{
struct can_config *hcan;
hcan = &((struct at32_can *) can->parent.user_data)->config;
struct rt_can_msg *pmsg = (struct rt_can_msg *) buf;
can_rx_message_type rx_message;
RT_ASSERT(can);
/* get data */
can_message_receive(hcan->can_x, (can_rx_fifo_num_type)fifo, &rx_message);
pmsg->data[0] = rx_message.data[0];
pmsg->data[1] = rx_message.data[1];
pmsg->data[2] = rx_message.data[2];
pmsg->data[3] = rx_message.data[3];
pmsg->data[4] = rx_message.data[4];
pmsg->data[5] = rx_message.data[5];
pmsg->data[6] = rx_message.data[6];
pmsg->data[7] = rx_message.data[7];
pmsg->len = rx_message.dlc;
pmsg->ide = rx_message.id_type; // 原本为id 修改为ide
if (rx_message.id_type == CAN_ID_STANDARD)
pmsg->id = rx_message.standard_id;
else
pmsg->id = rx_message.extended_id;// 原本是 ide 修改为id
pmsg->rtr = rx_message.frame_type;
pmsg->hdr = rx_message.filter_index;
return RT_EOK;
}
pwm 驱动代码
测试没有问题,可以完美的并入到rtt 的pwm 设备管理器中, 代码无缝移植
开启驱动流程总结
相比较原本stm32上的开发, at的库适配就没有提示, 主要靠查阅drv_xxx.c 中的宏, 去定义对应的宏, 然后修改at32_msp.c文件
以太网的配置流程
1 board.h 中, 开启如下几个宏
#define BSP_USING_ETH
#ifdef BSP_USING_ETH
#define PHY_USING_LAN8720A
#define BSP_USING_EMAC
2 修改at32_msp.c 中, 对io 口初始化的代码 修改至和板子对应的io 口, 查阅 参考手册 110页 , 获取 GPIO_MUX的具体值
spi 配置流程
按照board.h 中配置后, 修改at32_msp.c 中代码即可 使用 attach 的函数如下格式
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
rt_hw_spi_device_attach("spi1", NOR_FLASH_SPI_DEV_NAME, GPIOB, GPIO_PINS_6);
原作者:kid
|