mailbox数据发送和接收的过程

本文详细解析了嵌入式系统中Mailbox通信机制的核心流程,包括客户端如何通过mbox_send_message给控制器发送数据,控制器如何接收并处理这些数据,以及涉及的中断处理过程。
我们知道在client 在通过mbox_send_message给controller发送数据的时候必须指定channel。例如下面的code
	dc_sync->mbox = 
(&dc_sync->cl, 0);
	/* Populate data packet */
	/* sp.abc = 123; etc */
	/* Send message to remote in blocking mode */
	mbox_send_message(dc_sync->mbox, &sp);
	/* At this point 'sp' has been sent */
目前kernel提供了两种方法得到mailbox的channel
struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,const char *name);
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);
使用完成后调用mbox_free_channel 释放channel,这样别人就可以继续使用这个channel
void mbox_free_channel(struct mbox_chan *chan); /* may sleep */
其中mbox_request_channel_byname是mbox_request_channel的一个包装。所以这里直接看看mbox_request_channel
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
{
	struct device *dev = cl->dev;
	struct mbox_controller *mbox;
	struct of_phandle_args spec;
	struct mbox_chan *chan;
	unsigned long flags;
	int ret;


	spin_lock_irqsave(&chan->lock, flags);
	chan->msg_free = 0;
	chan->msg_count = 0;
	chan->active_req = NULL;
	chan->cl = cl;
	init_completion(&chan->tx_complete);

	//初始化chan,并最终startup
	ret = chan->mbox->ops->startup(chan);
	if (ret) {
		dev_err(dev, "Unable to startup the chan (%d)\n", ret);
		mbox_free_channel(chan);
		chan = ERR_PTR(ret);
	}
}
以之前的arm_mhu.c 中定义的mbox_chan_ops为例
static const struct mbox_chan_ops mhu_ops = {
	.send_data = mhu_send_data,
	.startup = mhu_startup,
	.shutdown = mhu_shutdown,
	.last_tx_done = mhu_last_tx_done,
};

static int mhu_startup(struct mbox_chan *chan)
{
	struct mhu_link *mlink = chan->con_priv;
	u32 val;
	int ret;

	val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
	writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
原来就是注册了一个中断,其回调函数是mhu_rx_interrupt
	ret = request_irq(mlink->irq, mhu_rx_interrupt,
			  IRQF_SHARED, "mhu_link", chan);
	if (ret) {
		dev_err(chan->mbox->dev,
			"Unable to acquire IRQ %d\n", mlink->irq);
		return ret;
	}

	return 0;
}
这个中断函数如下:
当client 给controller 通过mbox_send_message发送数据后,arm_mhu 会产生一个中断给cotroller。
static irqreturn_t mhu_rx_interrupt(int irq, void *p)
{
	struct mbox_chan *chan = p;
	struct mhu_link *mlink = chan->con_priv;
	u32 val;

	val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
	if (!val)
		return IRQ_NONE;
controller调用mbox_chan_received_data 就可以得到client发送来的数据
	mbox_chan_received_data(chan, (void *)&val);

	writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);

	return IRQ_HANDLED;
}
void mbox_chan_received_data(struct mbox_chan *chan, void *mssg)
{
	读去数据后,调用client的rx_callback 通知client
	/* No buffering the received data */
	if (chan->cl->rx_callback)
		chan->cl->rx_callback(chan->cl, mssg);
}


controller接收数据的flow 清楚了,再看看client是如何调用mbox_send_message 发送数据的
mbox_send_message->msg_submit
	if (chan->cl->tx_prepare)
		chan->cl->tx_prepare(chan->cl, data);
	/* Try to submit a message to the MBOX controller */
	err = chan->mbox->ops->send_data(chan, data);
	if (!err) {
		chan->active_req = data;
		chan->msg_count--;
	}
最终还是调用controll而的send_data 发送数据,本例controller的send_data函数为mhu_send_data
static int mhu_send_data(struct mbox_chan *chan, void *data)
{
	struct mhu_link *mlink = chan->con_priv;
	u32 *arg = data;
就是写controller的一个寄存器就行了,client写了之后后触发中断,controller会在中断中读到数据,并通过mbox_chan_received_data 通知client已经读取数据了
	writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);

	return 0;
}


<think>嗯,用户想了解STM32 HAL库中CAN总线的发送函数接收中断的实现方式。首先,我需要回忆一下HAL库中关于CAN模块的相关函数配置步骤。 首先,CAN的发送函数应该用的是HAL_CAN_AddTxMessage,这个函数需要指定CAN句柄、发送邮箱、数据以及长度。发送完成后可能会有回调函数,比如HAL_CAN_TxMailbox0CompleteCallback,用来处理发送完成的中断。 然后是接收中断。CAN的接收通常使用中断方式,需要先启动接收,使用HAL_CAN_ActivateNotification来使能接收中断,比如使能FIFO0的中断。当接收数据时,会触发HAL_CAN_RxFifo0MsgPendingCallback这个回调函数,用户需要在这里处理接收到的数据。 接下来,配置步骤的话,可能需要使用STM32CubeMX来初始化CAN外设,设置波特率、工作模式等。在代码中,可能需要开启CAN的中断,并编写相应的回调函数。 还需要注意,用户提到的引用资料是关于串口中断的,但CAN的中断机制有些不同,可能需要参考类似的HAL库结构,比如启动接收中断的方式类似于UART的HAL_UART_Receive_IT。但CAN有自己的FIFO过滤器设置,这部分可能需要详细说明。 另外,用户的问题可能涉及到如何配置过滤器,因为CAN总线通常需要过滤器的设置来处理不同的消息ID。不过用户主要问的是发送接收中断的实现,所以可能不需要深入讨论过滤器,但可能需要提及。 可能还需要提醒用户,在使用中断接收时,要确保及时重新启动接收,避免丢失后续的数据。类似于串口的不定长接收,但CAN是固定格式的帧,所以处理起来可能更直接。 最后,需要检查HAL库的版本,不同版本的HAL库可能在函数名或参数上有些差异,但通常HAL_CAN_AddTxMessage相关的回调函数应该是通用的。 总结一下,回答的结构应该是:先介绍发送函数的使用方法,然后说明如何配置接收中断,包括CubeMX的设置代码实现步骤,最后给出示例代码相关问题。同时,引用中的资料虽然主要关于串口,但HAL库的中断处理机制类似,可以适当参考。</think>### HAL库中CAN总线发送函数与接收中断实现 #### 一、CAN总线发送函数实现 在STM32 HAL库中,CAN总线数据发送主要通过$HAL\_CAN\_AddTxMessage()$函数实现。该函数将消息放入指定发送邮箱,并自动触发发送流程。核心参数包括: - CAN句柄指针 - 发送邮箱选择(CAN_TX_MAILBOX0/1/2) - 消息ID及格式(标准帧/扩展帧) - 数据缓冲区指针及长度 示例代码: ```c CAN_TxHeaderTypeDef TxHeader; uint8_t TxData[8] = {0x01, 0x02, 0x03, 0x04}; uint32_t TxMailbox; TxHeader.StdId = 0x123; // 标准ID TxHeader.IDE = CAN_ID_STD; // 标准帧 TxHeader.RTR = CAN_RTR_DATA; // 数据帧 TxHeader.DLC = 8; // 数据长度 HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox); ``` 发送完成可通过轮询标志位或中断处理: ```c // 发送完成中断回调函数 void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan) { // 处理发送完成事件 } ``` #### 二、接收中断实现 接收中断配置需三步操作: 1. **CubeMX配置**: - 启用CAN外设 - 配置波特率(常用1Mbps) - 设置过滤器模式(列表模式/掩码模式) - 开启接收中断(NVIC设置) 2. **启动接收中断**: ```c // 启动FIFO0接收中断 HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING); ``` 3. **接收中断回调函数**: ```c // 接收中断处理 void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef RxHeader; uint8_t RxData[8]; HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData); // 处理接收数据 if(RxHeader.StdId == 0x123) { // 执行对应操作 } } ``` #### 三、关键配置注意事项 1. **过滤器配置**: ```c CAN_FilterTypeDef filter; filter.FilterIdHigh = 0x123 << 5; // 标准ID左移5位 filter.FilterMaskIdHigh = 0x7FF <<5; // 标准帧掩码 filter.FilterMode = CAN_FILTERMODE_IDMASK; filter.FilterScale = CAN_FILTERSCALE_32BIT; filter.FilterBank = 0; filter.FilterFIFOAssignment = CAN_RX_FIFO0; HAL_CAN_ConfigFilter(&hcan, &filter); ``` 2. **中断优先级配置**: - 接收中断应设为合适优先级(建议高于发送中断) - 使用`HAL_NVIC_SetPriority(CAN_RX0_IRQn, 1, 0);` 3. **错误处理**: ```c void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) { // 处理总线错误 } ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值