移植 u-boot-2020.07 到 iTOP-4412(六)使用 UART 中断进行优化

写在前面

   经过前面第四篇文章(移植 u-boot-2020.07 到 iTOP-4412(四)支持中断),主要目的还是为了能在 u-boot 打开 UART 中断,改善 console 的手感。现在 UART 中断虽然已经正确打开使用,但是手感仍然极差,现象是接受到 RX 中断后,立即 TX 一个字母,可以观察到 RX 中断接收正常,但 TX 却没有按预期工作,可能会正确接收几个中断后才发送一次 TX。

   该现象目前没找到 BUG 在哪,准备换一个串口转 usb 的线,如果是这个原因的话那真是太坑了(CH340 一生黑),之后更新结果。

后记:
   果然 CH340 就是比较 LJ,换了 40 块钱的绿联 serial 转 usb 就好了。

   所以把波特率改到了 230400 ,特别好用。

一、目标

  1. 提供通用中断例程
  2. 打开 UART 中断,使用 UART 的中断进行 RXTX。
  3. 软件提供 UART RXTX buff,系统 printf 只将字符写入该 buff ,发送接收由中断进行
  4. 提供 spin_lock 保护 buff,因为 buff 为中断和非中断都使用的共享内存。

二、中断通用例程

   Exynos-4412 共支持 160 个中断源,当然我们这里只对 irq 进行支持。

   对中断进行统一的管理,先注册中断 callback,进入中断后找到对应的 callback。

   pt_regs 参数为 SVC/USR 模式的寄存器信息。

typedef int (*irq_cb_t) (int irq, void * data);
struct irq_entry
{
	irq_cb_t callback;
	void *   data;
};
static struct irq_entry irq_list[MAX_IRQ_NUMBER];

int register_irq(int irq, irq_cb_t cb, void * data)
{
	if(irq < 0 || irq >= MAX_IRQ_NUMBER)
		return -EFAULT;
	if(cb == NULL)
		return -EFAULT;
	if(irq_list[irq].callback != NULL)
		return -EFAULT;

	irq_list[irq].callback = cb;
	irq_list[irq].data = data;
	return 0;
}

int xhr4412_do_irq(struct pt_regs *pt_regs)
{
	static ulongx irq_count = 0;
	static ulongx irq_null_cb_count = 0;
	struct irq_entry * entry;
	int cpu = getl(ICCIAR_CPU0);
	int irq = cpu & 0x3FF;
	int ret;
	cpu &= ~0x3FF;
	irq_count++;
	if(irq < MAX_IRQ_NUMBER) {
		entry = &irq_list[irq];

		if(entry->callback != NULL) {
			ret = entry->callback(irq, entry->data);
		} else {
			printf("\nnull irq_cb, irq_count = (%lu/%lu) cpu = %d irq = %d\n",
				++irq_null_cb_count, irq_count, cpu, irq);
			ret = -ENOTTY;
		}
	} else {
		printf("\nirq num is invalid, cpu = %d irq = %d\n", cpu, irq);
		ret = -EFAULT;
	}
	setl(ICCEOIR_CPU0, cpu | irq);
	return ret;
}

三、UART 中断

   注册 UART 中断处理函数。初始化 UART ,打开 UART 中断使能,CPU 中断使能等。

   这里要主要一下 u-boot 对 serial 的初始化时机,这个问题卡了我一些时间。可以多读一下 u-boot 的官方文档和源码。

   同时涉及了设备树、u-boot DM 模型(类似 linux)、重定位等方面。

   简单来说 serial 会在 common/board_f.c 初始化一次,然后在 common/board_r.c 再初始化一次,第一次初始化时,代码还没有重定位完毕,所以不能使用全局变量,这时不应该使用软件 buff。

   这里我处理得并不好,只是简单的通过 global_data 来实现了区分两次初始化,更一般的做法是应该遵循 u-boot 的 DM 模型。

四、共享 buff

   因为 buff 是通过队列的形式保存数据,所以中断和非中断都会对它操作,所以需要对共享的部分进行互斥。我自己实现了简单的 lock,不过 u-boot 也有提供 linux 类似的 spin_lock。

   不知道如何测试是否正确,不过目前看起来还没有问题,如果发现问题也请联系我,谢谢。

static inline void spin_lock_xhr(void)
{
	ulongx cpsr = 0;
	ulongx mode;
	__asm__ __volatile__ ( 
		"mrs %0, cpsr\n\t"
		"and %1, %0, #0x1F\n\t"
		: "+r" (cpsr), "=r" (mode)
		:);
	if(mode == ARM_MOD_SVC || mode == ARM_MOD_USR)
	{
		__asm__ __volatile__ ( 
			"orr %0, %0, #0x80\n\t"
			"msr cpsr, %0\n\t" : : "r" (cpsr));
	}
}

static inline void spin_unlock_xhr(void)
{
	ulongx cpsr = 0;
	ulongx mode;
	__asm__ __volatile__ ( 
		"mrs %0, cpsr\n\t"
		"and %1, %0, #0x1F\n\t"
		: "+r" (cpsr), "=r" (mode)
		:);
	if(mode == ARM_MOD_SVC || mode == ARM_MOD_USR)
	{
		__asm__ __volatile__ ( 
			"bic %0, %0, #0x80\n\t"
			"msr cpsr, %0\n\t" : : "r" (cpsr));
	}
}

五、效果

目前还是效果不佳,虽然是中断,但是感觉是硬件有问题?
在这里插入图片描述
在这里插入图片描述
效果不佳,先加一个配置选项,默认不选该功能。
在这里插入图片描述

六、最后

   果然,几块钱的 CH340 不太行,换了 40 块钱的绿联后就好了。。也不会感觉卡顿了。。

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值