#define GPIO_TO_PIN(bank, gpio) (8 * (bank) + (gpio))
海思gpio引脚每组总是从0~7,而且引脚从头都有唯一编号;通过上面公式转换到对应编号;
引脚对应硬件原理图;
//#define GPIO_TO_PIN(bank, gpio) (8 * (bank) + (gpio))
#include
#include
#define SPI_CSN 87 // gpio10_7;
#define SPI_CLK 86 // gpio10_6
#define SPI_MOSI 52 // gpio6_4;
#define SPI_MISO 53 // gpio6_5;
#define RESET 51 // gpio6_3
//gpio_direction_output为内核函数,参数1:引脚编号 参数2:值(1:输出高;0:输出低)
#define SET_CS_HIGH gpio_direction_output(SPI_CSN, 1)
#define SET_CS_LOW gpio_direction_output(SPI_CSN, 0)
#define SET_SCK_HIGH gpio_direction_output(SPI_CLK, 1)
#define SET_SCK_LOW gpio_direction_output(SPI_CLK, 0)
#define SET_MOSI_HIGH gpio_direction_output(SPI_MOSI, 1)
#define SET_MOSI_LOW gpio_direction_output(SPI_MOSI, 0)
#define SET_RESET_HIGH gpio_direction_output(RESET, 1)
#define SET_RESET_LOW gpio_direction_output(RESET, 0)
#define GET_MISO gpio_get_value(SPI_MISO)
static int spi_gpio_init(void)
{
int err = 0;
err = gpio_request(SPI_CSN, "SPI_CSN");
if (err < 0) {
printk("gpio failed to request SPI_CSN: %d\n", err);
goto fail;
}
err = gpio_request(SPI_CLK, "SPI_CLK");
if (err < 0) {
printk("gpio failed to request SPI_CLK: %d\n", err);
goto fail;
}
err = gpio_request(SPI_MOSI, "SPI_MOSI");
if (err < 0) {
printk("gpio failed to request SPI_MOSI: %d\n", err);
goto fail;
}
err = gpio_request(SPI_MISO, "SPI_MISO");
if (err < 0) {
printk("gpio failed to request SPI_MISO: %d\n", err);
goto fail;
}
err = gpio_request(RESET, "RESET");
if (err < 0) {
printk("gpio failed to request RESET: %d\n", err);
goto fail;
}
fail:
return err;
}
static void spi_gpio_free(void)
{
gpio_free(SPI_CSN);
gpio_free(SPI_CLK);
gpio_free(SPI_MOSI);
gpio_free(SPI_MISO);
gpio_free(RESET);
}
1> 读写前认真分析时序图;弄清楚CPOL和CPHA对应的四种模式,这是读写寄存器实现的关键!!!
2> 读写时需查看是MSB还是LSB优先; 如0x1010 1100 若是LSB优先则先传输低位0;MSB优先则先传输高位1;算法处理不同;
本图以CPOL=1 CPHA=1 LSB first为例:
延时需按照图中st_SI 和hd_SI等给出值处理;
void delay_ms(unsigned int mscount)
{
mdelay(mscount);
}
void delay_us(unsigned char uscount)
{
udelay(uscount);
}
void delay_ns(unsigned char nscount)
{
ndelay(nscount);
}
//CPOL=1 CPHA=1 LSB first
static void spi_send_data(unsigned char addr, unsigned char data)
{
printk("send addr[%x] data[%x]\n",addr, data);
unsigned int i;
//SET_CS_HIGH;
//SET_SCK_HIGH;
//SET_MOSI_HIGH;
//delay_us(20);
SET_CS_LOW;
//delay_us(20);
for (i = 0; i < 8; ++i)
{
SET_SCK_LOW;
//delay_us(10);
delay_ns(400);
if (addr & (0x01 << i))
{
//printk("spi send addr high\n");
SET_MOSI_HIGH;
}
else
{
//printk("spi send addr low\n");
SET_MOSI_LOW;
}
//delay_us(10);
delay_ns(400);
SET_SCK_HIGH;
delay_ns(400);
//delay_us(10);
}
for (i = 0; i < 8; ++i)
{
SET_SCK_LOW;
//delay_us(10);
delay_ns(400);
if (data & (0x01 << i))
{
SET_MOSI_HIGH;
//printk("spi send data high\n");
}
else
{
SET_MOSI_LOW;
//printk("spi send data low\n");
}
//delay_us(10);
delay_ns(400);
SET_SCK_HIGH;
delay_ns(400);
//delay_us(10);
}
SET_CS_HIGH;
SET_MOSI_HIGH;
}
static unsigned char spi_read_data(void)
{
unsigned char i,j,front_data;
unsigned char value = 0;
SET_CS_HIGH;
delay_us(20);
SET_CS_LOW;
delay_us(20);
front_data = 0x81;
for (i = 0; i < 8; ++i)
{
SET_SCK_LOW;
//delay_us(10);
delay_ns(400);
if (front_data & (0x01 << i))
{
SET_MOSI_HIGH;
//printk("spi rw addr high\n");
}
else
{
SET_MOSI_LOW;
//printk("spi rw addr low\n");
}
//delay_us(10);
delay_ns(400);
SET_SCK_HIGH;
//delay_us(10);
delay_ns(400);
}
delay_us(10);
for(j=0; j<8; j++) // 8 Data
{
SET_SCK_LOW;
delay_ns(400);
//delay_us(10);
SET_SCK_HIGH;
delay_ns(400);
//delay_us(10);
printk("read sdi = %d\n", GET_MISO);
value |= (GET_MISO << j);
//delay_us(10);
delay_ns(400);
}
SET_CS_HIGH;
return value;
}
测试时可先写后读,若一致则通信成功;
若通常失败:
(1)可单独控制各个引脚,逐步排查问题所在;
(2) 控制延时,示波器抓波形分析;
相对于ioremap方式,上述方式更简单;
static char* g_reg_crg_base = 0;
static char* g_reg_gpio_base = 0;
...
static int init_map_reg(void)
{
g_reg_crg_base = (void*)ioremap(0x12010000, 0x10000);
if (g_reg_crg_base == NULL) {
return -1;
}
g_reg_gpio_base = (void*)ioremap(0x120D0000, 0x10000);
if (g_reg_gpio_base == NULL) {
return -1;
}
}
static void exit_unmap_reg(void)
{
if (g_reg_crg_base != NULL) {
iounmap(g_reg_crg_base);
g_reg_crg_base = 0;
}
if (g_reg_gpio_base != NULL) {
iounmap(g_reg_gpio_base);
g_reg_gpio_base = 0;
}
}
int init_pin_mux(void)
{
writel(0x00182c00, g_reg_crg_base + 0x00A0);
...
writel(0x20, g_reg_gpio_base + 0x0080);
...
}