drv_spi.c 5.4 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2022, RT-Thread Development Team
3 4 5 6 7 8
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2017-06-05     tanek        first implementation.
9 10 11
 * 2018-04-19     misonyo      Porting for v85xxf30x
 * 2019-03-31     xuzhuoyi     Porting for v85xxe230
 * 2021-09-21     zhuxw        Porting for v85xx
12 13 14 15 16 17 18 19 20
 */

#include "drv_spi.h"
#include "board.h"
#include <rtthread.h>

#if defined(RT_USING_SPI) && defined(RT_USING_PIN)
#include <rtdevice.h>

21
#if !defined(RT_USING_SPI1) && !defined(RT_USING_SPI2)
22 23 24 25 26 27 28
#error "Please define at least one SPIx"
#endif

/* private rt-thread spi ops function */
static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration);
static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message);

29
static struct rt_spi_ops v85xx_spi_ops =
30 31 32 33 34 35 36
{
    configure,
    xfer
};

static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration)
{
37
    SPI_InitType spi_init_struct;
38 39 40 41 42 43

    rt_uint32_t spi_periph = (rt_uint32_t)device->bus->parent.user_data;

    RT_ASSERT(device != RT_NULL);
    RT_ASSERT(configuration != RT_NULL);

44
    if(configuration->data_width > 8)
45 46 47 48 49 50 51 52 53 54
    {
        return RT_EIO;
    }

    {
        rt_uint32_t spi_apb_clock;
        rt_uint32_t max_hz;

        max_hz = configuration->max_hz;

55
        spi_apb_clock = CLK_GetPCLKFreq();
56 57 58

        if(max_hz >= spi_apb_clock/2)
        {
59
            spi_init_struct.ClockDivision = SPI_CLKDIV_2;
60 61 62
        }
        else if (max_hz >= spi_apb_clock/4)
        {
63
            spi_init_struct.ClockDivision = SPI_CLKDIV_4;
64 65 66
        }
        else if (max_hz >= spi_apb_clock/8)
        {
67
            spi_init_struct.ClockDivision = SPI_CLKDIV_8;
68 69 70
        }
        else if (max_hz >= spi_apb_clock/16)
        {
71
            spi_init_struct.ClockDivision = SPI_CLKDIV_16;
72 73 74
        }
        else if (max_hz >= spi_apb_clock/32)
        {
75
            spi_init_struct.ClockDivision = SPI_CLKDIV_32;
76 77 78
        }
        else if (max_hz >= spi_apb_clock/64)
        {
79
            spi_init_struct.ClockDivision = SPI_CLKDIV_64;
80 81 82
        }
        else
        {
83 84
            /*  min prescaler 128 */
            spi_init_struct.ClockDivision = SPI_CLKDIV_128;
85 86 87 88 89 90
        }
    } /* baudrate */

    switch(configuration->mode & RT_SPI_MODE_3)
    {
    case RT_SPI_MODE_0:
91 92
        spi_init_struct.SPH = SPI_SPH_0;
        spi_init_struct.SPO = SPI_SPO_0;
93 94
        break;
    case RT_SPI_MODE_1:
95 96
        spi_init_struct.SPH = SPI_SPH_1;
        spi_init_struct.SPO = SPI_SPO_0;
97 98
        break;
    case RT_SPI_MODE_2:
99 100
        spi_init_struct.SPH = SPI_SPH_0;
        spi_init_struct.SPO = SPI_SPO_1;
101 102
        break;
    case RT_SPI_MODE_3:
103 104
        spi_init_struct.SPH = SPI_SPH_1;
        spi_init_struct.SPO = SPI_SPO_1;
105 106 107
        break;
    }

108
    if(!(configuration->mode & RT_SPI_MSB))
109
    {
110
        return RT_EIO;
111 112
    }

113 114
    spi_init_struct.Mode = SPI_MODE_MASTER;
    spi_init_struct.CSNSoft = SPI_CSNSOFT_ENABLE;
115

116
    SPI_Init((SPI_TypeDef*)spi_periph, &spi_init_struct);
117

118
    SPI_Cmd((SPI_TypeDef*)spi_periph, ENABLE);
119 120 121 122 123 124

    return RT_EOK;
};

static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message)
{
125
    rt_base_t v85xx_cs_pin = (rt_base_t)device->parent.user_data;
126 127 128
    rt_uint32_t spi_periph = (rt_uint32_t)device->bus->parent.user_data;
    struct rt_spi_configuration * config = &device->config;

idk500's avatar
idk500 已提交
129
    RT_ASSERT(device != RT_NULL);
130
    RT_ASSERT(message != RT_NULL);
131 132 133 134

    /* take CS */
    if(message->cs_take)
    {
135
        rt_pin_write(v85xx_cs_pin, PIN_LOW);
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
        DEBUG_PRINTF("spi take cs\n");
    }

    {
        if(config->data_width <= 8)
        {
            const rt_uint8_t * send_ptr = message->send_buf;
            rt_uint8_t * recv_ptr = message->recv_buf;
            rt_uint32_t size = message->length;

            DEBUG_PRINTF("spi poll transfer start: %d\n", size);

            while(size--)
            {
                rt_uint8_t data = 0xFF;

                if(send_ptr != RT_NULL)
                {
                    data = *send_ptr++;
                }

                //Wait until the transmit buffer is empty
158
                while(RESET == SPI_GetStatus((SPI_TypeDef*)spi_periph, SPI_STS_TXEMPTY));
159
                // Send the byte
160
                SPI_SendData((SPI_TypeDef*)spi_periph, data);
161 162

                //Wait until a data is received
163
                while(RESET == SPI_GetStatus((SPI_TypeDef*)spi_periph, SPI_STS_RNE));
164
                // Get the received data
165
                data = SPI_ReceiveData((SPI_TypeDef*)spi_periph);
166 167 168 169 170 171 172 173 174 175 176 177 178

                if(recv_ptr != RT_NULL)
                {
                    *recv_ptr++ = data;
                }
            }
            DEBUG_PRINTF("spi poll transfer finsh\n");
        }
    }

    /* release CS */
    if(message->cs_release)
    {
179
        rt_pin_write(v85xx_cs_pin, PIN_HIGH);
180 181 182 183 184 185
        DEBUG_PRINTF("spi release cs\n");
    }

    return message->length;
};

186
int v85xx_hw_spi_init(void)
187 188
{
    int result = 0;
189
#ifdef RT_USING_SPI1
190
    static struct rt_spi_bus spi_bus0;
191
    spi_bus0.parent.user_data = (void *)SPI1;
192

193
    result = rt_spi_bus_register(&spi_bus0, "spi1", &v85xx_spi_ops);
194

195
#endif
196

197
#ifdef RT_USING_SPI2
198
    static struct rt_spi_bus spi_bus1;
199
    spi_bus1.parent.user_data = (void *)SPI2;
200

201
    result = rt_spi_bus_register(&spi_bus1, "spi2", &v85xx_spi_ops);
202 203 204 205

#endif
    return result;
}
206
INIT_BOARD_EXPORT(v85xx_hw_spi_init);
207
#endif