硅天下科技

硅天下科技

1个粉丝

38

问答

0

专栏

9

资料

硅天下科技  发布于  2020-09-07 23:03:23
采纳率 0%
38个问答
2758

【Hi3516DV300】之SPI的实现

 
1 查询SPI相关的寄存器

《用户指南.pdf》和《3516DV300_PINOUT_EN.xlsx》查询如下
/*
SPI0 基地址是 0x120C_0000
SPI1 基地址是 0x120C_1000
SPI2 基地址是 0x120C_2000
*/
#define SSP_BASE            (0x120c1000)

/*
SPI1 pinmux
*/
#define SPI1_SCLK           (0x112F0020)
#define SPI1_SDO            (0x112F0024)
#define SPI1_CSN0                  (0x112f0028)
#define SPI1_SDI            (0x112F002C)

/*
PERI_CRG111 - SPI Clock Control
*/
#define PERI_CRG111         (0x120101BC)

/*
MISC_CTRL0  - SP1_CSN0 Check
*/
#define MISC_CTRL0                 (0x12030000+0x0000)

#define SSP_SIZE             0x1000          // 4KB
#define DEFAULT_MD_LEN       (128)
#define IO_ADDRESS_VERIFY(x) (x)


/* SSP register definition .*/
#define SSP_CR0              IO_ADDRESS_VERIFY(SSP_BASE + 0x00)
#define SSP_CR1              IO_ADDRESS_VERIFY(SSP_BASE + 0x04)
#define SSP_DR               IO_ADDRESS_VERIFY(SSP_BASE + 0x08)
#define SSP_SR               IO_ADDRESS_VERIFY(SSP_BASE + 0x0C)
#define SSP_CPSR             IO_ADDRESS_VERIFY(SSP_BASE + 0x10)
#define SSP_IMSC             IO_ADDRESS_VERIFY(SSP_BASE + 0x14)
#define SSP_RIS              IO_ADDRESS_VERIFY(SSP_BASE + 0x18)
#define SSP_MIS              IO_ADDRESS_VERIFY(SSP_BASE + 0x1C)
#define SSP_ICR              IO_ADDRESS_VERIFY(SSP_BASE + 0x20)
#define SSP_DMACR            IO_ADDRESS_VERIFY(SSP_BASE + 0x24)
#define SSP_SPITXFIFOCR      IO_ADDRESS_VERIFY(SSP_BASE + 0x28)
#define SSP_SPIRXFIFOCR      IO_ADDRESS_VERIFY(SSP_BASE + 0x2C)


#define SPI_SR_BSY           (0x1 << 4)/* spi busy flag */
#define SPI_SR_TFE           (0x1 << 0)/* Whether to send fifo is empty */
#define SPI_DATA_WIDTH       (9)
#define SPI_SPO              (1)/* 极性 */
#define SPI_SPH              (1)/* 相性 */
#define SPI_SCR              (0)//(8)
#define SPI_CPSDVSR          (2)//(8)
#define SPI_FRAMEMODE        (0)

#define MAX_WAIT 10000

2 SPI的管脚复用
static void spi1_pinmux()
{
  ssp_writew(SPI1_SCLK, 0x4f1);
  ssp_writew(SPI1_SDO, 0x4f1);
  ssp_writew(SPI1_SDI, 0x4f1);
  spi1_csn0_pinmux();

  printf("spi1_pinmux\n");
}

3 SPI的时钟开启

独立软复位:由寄存器 PERI_CRG111 的 bit[17:15] 控制。相应位写“ 0 ”, SPI 退出软复位;相应位写“ 1 ”, SPI 进入软复位。上电缺省值为 0 。
时钟门控:由寄存器 PERI_CRG111 的 bit[14:12] 控制。相应位写“ 0 ”,关闭时钟;相应位写“ 1 ”,打开时钟。上电缺省值为 1 。

PERI_CRG111的第13bit为SPI1始终们控配置寄存器

    0: 关闭时钟

    1: 打开时钟
static void spi1_open_clock()
{
  unsigned int peri_cfg111;
  ssp_readw(PERI_CRG111, peri_cfg111);
  ssp_writew(PERI_CRG111, peri_cfg111|0x1<<13);

  printf("spi1_open_clock\n");
}

4 SPI1_CSN0启用和配置

MISC_CTRL0的第2bit为SPI1信号输出片选选择

    0: SPI1_CSN0

    1: SPI1_CSN1

MISC_CTRL0的第3bit为SPI1片选信号0极性控制

    0: SPI1_CSN0低有效

    1: SPI1_CSN0高有效
static void spi1_csn0_pinmux()
{
            // 复选spi_csn0
        ssp_writew(SPI1_CSN0, 0x0501);

        // 配置csn0低有效 且选择片选0
        unsigned int misc_ctrl0;
        ssp_readw(MISC_CTRL0, misc_ctrl0);
        misc_ctrl0 &= ~(0x1<<3); // 低有效
        misc_ctrl0 &= ~(0x1<<2); // 片选0
        ssp_writew(MISC_CTRL0, misc_ctrl0);
}

5 实现读写寄存器函数

#ifdef __HuaweiLite__
#define  ssp_readw(addr,ret)            (ret =(*(volatile unsigned int *)(addr)))
#define  ssp_writew(addr,value)         ((*(volatile unsigned int *)(addr)) = (value))
#else
static const char dev[]="/dev/mem";

static void write_reg(unsigned int Addr, unsigned int Value)
{
    int fd = open (dev, O_RDWR | O_SYNC);
    if (fd < 0)
    {
        printf("open %s error!\n", dev);
        return ;
    }
   
    /* addr align in page_size(4K) */
    unsigned long phy_addr_in_page;
    unsigned long page_diff;
    phy_addr_in_page = Addr & PAGE_SIZE_MASK;
    page_diff = Addr - phy_addr_in_page;

    /* size in page_size */
    unsigned long size_in_page;
    unsigned long size = PAGE_SIZE;
    size_in_page =((size + page_diff - 1) & PAGE_SIZE_MASK) + PAGE_SIZE;
   
    void *addr = mmap((void *)0, size_in_page, PROT_READ|PROT_WRITE, MAP_SHARED, fd, phy_addr_in_page);
    if (addr == MAP_FAILED)
    {
        printf("mmap @ 0x%x error!\n", phy_addr_in_page);
        close(fd);
        return;
    }

    unsigned int *addr_cur = (unsigned int *)(addr+page_diff);

    *addr_cur = Value;
   
    /* munmap */
    if(munmap(addr, size_in_page) != 0 )
    {
        printf("munmap failed!\n");
    }

    close(fd);
    //printf("ssp_write_reg %x %d\n", Addr, Value);
}

static unsigned int read_reg(unsigned int Addr)
{
    unsigned int Value = 0;
    int fd = open (dev, O_RDWR | O_SYNC);
    if (fd < 0)
    {
        printf("open %s error!\n", dev);
        return -1;
    }
   
    /* addr align in page_size(4K) */
    unsigned long phy_addr_in_page;
    unsigned long page_diff;
    phy_addr_in_page = Addr & PAGE_SIZE_MASK;
    page_diff = Addr - phy_addr_in_page;

    /* size in page_size */
    unsigned long size_in_page;
    unsigned long size = PAGE_SIZE;
    size_in_page =((size + page_diff - 1) & PAGE_SIZE_MASK) + PAGE_SIZE;
   
    void *addr = mmap((void *)0, size_in_page, PROT_READ|PROT_WRITE, MAP_SHARED, fd, phy_addr_in_page);
    if (addr == MAP_FAILED)
    {
        printf("mmap @ 0x%x error!\n", phy_addr_in_page);
        close(fd);
        return -1;
    }

    unsigned int *addr_cur = (unsigned int *)(addr+page_diff);

    Value = *addr_cur;
   
    /* munmap */
    if(munmap(addr, size_in_page) != 0 )
    {
        printf("munmap failed!\n");
    }

    close(fd);
    //printf("ssp_read_reg %x %d\n", Addr, Value);
    return Value;
}

#define  ssp_readw(addr,ret)            (ret=read_reg(addr))
#define  ssp_writew(addr,value)         (write_reg(addr, value))
#endif

未完待续……
我来回答
回答0个
时间排序
认可量排序
易百纳技术社区暂无数据
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区