drv_spi.c 8.4 KB
Newer Older
T
tanek liang 已提交
1
/*
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
T
tanek liang 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
T
tanek liang 已提交
5 6 7 8 9
 *
 * Change Logs:
 * Date           Author       Notes
 * 2017-06-05     tanek        first implementation.
 */
mysterywolf's avatar
mysterywolf 已提交
10

T
tanek liang 已提交
11 12 13 14 15
#include "drv_spi.h"

#include <board.h>
#include <finsh.h>

T
tanek liang 已提交
16 17 18 19 20 21 22 23
#ifdef RT_USING_SPI

#if !defined(RT_USING_SPI0) && !defined(RT_USING_SPI1) && \
    !defined(RT_USING_SPI2) && !defined(RT_USING_SPI3)  && \
    !defined(RT_USING_SPI4) && !defined(RT_USING_SPI5)
#error "Please define at least one SPIx"
#endif

T
tanek liang 已提交
24 25 26 27 28 29 30
//#define DEBUG

#define ARR_LEN(__N)      (sizeof(__N) / sizeof(__N[0]))

#ifdef DEBUG
#define DEBUG_PRINTF(...)   rt_kprintf(__VA_ARGS__)
#else
mysterywolf's avatar
mysterywolf 已提交
31
#define DEBUG_PRINTF(...)
T
tanek liang 已提交
32 33 34 35 36 37
#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);

T
tanek liang 已提交
38
static struct rt_spi_ops gd32_spi_ops =
T
tanek liang 已提交
39 40 41 42 43 44 45 46
{
    configure,
    xfer
};

static rt_err_t configure(struct rt_spi_device* device,
                          struct rt_spi_configuration* configuration)
{
mysterywolf's avatar
mysterywolf 已提交
47
    struct rt_spi_bus * spi_bus = (struct rt_spi_bus *)device->bus;
T
tanek liang 已提交
48
    struct gd32f4_spi *f4_spi = (struct gd32f4_spi *)spi_bus->parent.user_data;
mysterywolf's avatar
mysterywolf 已提交
49

T
tanek liang 已提交
50 51 52 53 54
    spi_parameter_struct spi_init_struct;

    uint32_t spi_periph = f4_spi->spi_periph;


mysterywolf's avatar
mysterywolf 已提交
55 56
    RT_ASSERT(device != RT_NULL);
    RT_ASSERT(configuration != RT_NULL);
T
tanek liang 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127

    /* data_width */
    if(configuration->data_width <= 8)
    {
        spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
    }
    else if(configuration->data_width <= 16)
    {
        spi_init_struct.frame_size = SPI_FRAMESIZE_16BIT;
    }
    else
    {
        return RT_EIO;
    }

    /* baudrate */
    {
        rcu_clock_freq_enum spi_src;
        uint32_t spi_apb_clock;
        uint32_t max_hz;

        max_hz = configuration->max_hz;

        DEBUG_PRINTF("sys   freq: %d\n", HAL_RCC_GetSysClockFreq());
        DEBUG_PRINTF("pclk2 freq: %d\n", HAL_RCC_GetPCLK2Freq());
        DEBUG_PRINTF("max   freq: %d\n", max_hz);

        if (spi_periph == SPI1 || spi_periph == SPI2)
        {
            spi_src = CK_APB1;
        }
        else
        {
            spi_src = CK_APB2;
        }
        spi_apb_clock = rcu_clock_freq_get(spi_src);

        if(max_hz >= spi_apb_clock/2)
        {
            spi_init_struct.prescale = SPI_PSC_2;
        }
        else if (max_hz >= spi_apb_clock/4)
        {
            spi_init_struct.prescale = SPI_PSC_4;
        }
        else if (max_hz >= spi_apb_clock/8)
        {
            spi_init_struct.prescale = SPI_PSC_8;
        }
        else if (max_hz >= spi_apb_clock/16)
        {
            spi_init_struct.prescale = SPI_PSC_16;
        }
        else if (max_hz >= spi_apb_clock/32)
        {
            spi_init_struct.prescale = SPI_PSC_32;
        }
        else if (max_hz >= spi_apb_clock/64)
        {
            spi_init_struct.prescale = SPI_PSC_64;
        }
        else if (max_hz >= spi_apb_clock/128)
        {
            spi_init_struct.prescale = SPI_PSC_128;
        }
        else
        {
            /*  min prescaler 256 */
            spi_init_struct.prescale = SPI_PSC_256;
        }
    } /* baudrate */
mysterywolf's avatar
mysterywolf 已提交
128

129
    switch(configuration->mode & RT_SPI_MODE_3)
T
tanek liang 已提交
130 131 132 133 134 135
    {
    case RT_SPI_MODE_0:
        spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
        break;
    case RT_SPI_MODE_1:
        spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
mysterywolf's avatar
mysterywolf 已提交
136
        break;
T
tanek liang 已提交
137 138
    case RT_SPI_MODE_2:
        spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE;
mysterywolf's avatar
mysterywolf 已提交
139
        break;
T
tanek liang 已提交
140 141 142 143
    case RT_SPI_MODE_3:
        spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
        break;
    }
mysterywolf's avatar
mysterywolf 已提交
144

T
tanek liang 已提交
145 146 147 148 149 150 151 152 153
    /* MSB or LSB */
    if(configuration->mode & RT_SPI_MSB)
    {
        spi_init_struct.endian = SPI_ENDIAN_MSB;
    }
    else
    {
        spi_init_struct.endian = SPI_ENDIAN_LSB;
    }
mysterywolf's avatar
mysterywolf 已提交
154

T
tanek liang 已提交
155 156 157
    spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode = SPI_MASTER;
    spi_init_struct.nss = SPI_NSS_SOFT;
mysterywolf's avatar
mysterywolf 已提交
158

T
tanek liang 已提交
159 160 161 162 163
    spi_crc_off(spi_periph);

    /* init SPI */
    spi_init(spi_periph, &spi_init_struct);
    /* Enable SPI_MASTER */
mysterywolf's avatar
mysterywolf 已提交
164 165
    spi_enable(spi_periph);

T
tanek liang 已提交
166 167 168 169 170
    return RT_EOK;
};

static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message)
{
T
tanek liang 已提交
171 172
    struct rt_spi_bus * gd32_spi_bus = (struct rt_spi_bus *)device->bus;
    struct gd32f4_spi *f4_spi = (struct gd32f4_spi *)gd32_spi_bus->parent.user_data;
T
tanek liang 已提交
173
    struct rt_spi_configuration * config = &device->config;
T
tanek liang 已提交
174
    struct gd32_spi_cs * gd32_spi_cs = device->parent.user_data;
T
tanek liang 已提交
175 176
    uint32_t spi_periph = f4_spi->spi_periph;

mysterywolf's avatar
mysterywolf 已提交
177 178 179
    RT_ASSERT(device != NULL);
    RT_ASSERT(message != NULL);

T
tanek liang 已提交
180 181 182
    /* take CS */
    if(message->cs_take)
    {
T
tanek liang 已提交
183
        gpio_bit_reset(gd32_spi_cs->GPIOx, gd32_spi_cs->GPIO_Pin);
T
tanek liang 已提交
184 185 186 187 188 189 190 191 192
        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;
mysterywolf's avatar
mysterywolf 已提交
193

T
tanek liang 已提交
194 195 196 197 198 199 200 201 202 203
            DEBUG_PRINTF("spi poll transfer start: %d\n", size);

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

                if(send_ptr != RT_NULL)
                {
                    data = *send_ptr++;
                }
mysterywolf's avatar
mysterywolf 已提交
204

T
tanek liang 已提交
205
                // Todo: replace register read/write by gd32f4 lib
T
tanek liang 已提交
206 207 208
                //Wait until the transmit buffer is empty
                while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE));
                // Send the byte
mysterywolf's avatar
mysterywolf 已提交
209
                spi_i2s_data_transmit(spi_periph, data);
T
tanek liang 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240

                //Wait until a data is received
                while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE));
                // Get the received data
                data = spi_i2s_data_receive(spi_periph);

                if(recv_ptr != RT_NULL)
                {
                    *recv_ptr++ = data;
                }
            }
            DEBUG_PRINTF("spi poll transfer finsh\n");
        }
        else if(config->data_width <= 16)
        {
            const rt_uint16_t * send_ptr = message->send_buf;
            rt_uint16_t * recv_ptr = message->recv_buf;
            rt_uint32_t size = message->length;

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

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

                //Wait until the transmit buffer is empty
                while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE));
                // Send the byte
mysterywolf's avatar
mysterywolf 已提交
241
                spi_i2s_data_transmit(spi_periph, data);
T
tanek liang 已提交
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

                //Wait until a data is received
                while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE));
                // Get the received data
                data = spi_i2s_data_receive(spi_periph);

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

    /* release CS */
    if(message->cs_release)
    {
mysterywolf's avatar
mysterywolf 已提交
259
        gpio_bit_set(gd32_spi_cs->GPIOx, gd32_spi_cs->GPIO_Pin);
T
tanek liang 已提交
260 261 262 263 264 265 266 267 268
        DEBUG_PRINTF("spi release cs\n");
    }

    return message->length;
};


static struct rt_spi_bus spi_bus[];

T
tanek liang 已提交
269
static const struct gd32f4_spi spis[] = {
T
tanek liang 已提交
270 271 272
#ifdef RT_USING_SPI0
    {SPI0, RCU_SPI0, &spi_bus[0]},
#endif
mysterywolf's avatar
mysterywolf 已提交
273

T
tanek liang 已提交
274 275 276 277 278 279 280 281 282 283 284
#ifdef RT_USING_SPI1
    {SPI1, RCU_SPI1, &spi_bus[1]},
#endif

#ifdef RT_USING_SPI2
    {SPI2, RCU_SPI2, &spi_bus[2]},
#endif

#ifdef RT_USING_SPI3
    {SPI3, RCU_SPI3, &spi_bus[3]},
#endif
mysterywolf's avatar
mysterywolf 已提交
285

T
tanek liang 已提交
286 287 288
#ifdef RT_USING_SPI4
    {SPI4, RCU_SPI4, &spi_bus[4]},
#endif
mysterywolf's avatar
mysterywolf 已提交
289

T
tanek liang 已提交
290 291 292 293 294 295 296
#ifdef RT_USING_SPI5
    {SPI5, RCU_SPI5, &spi_bus[5]},
#endif
};

static struct rt_spi_bus spi_bus[ARR_LEN(spis)];

T
tanek liang 已提交
297
/** \brief init and register gd32 spi bus.
T
tanek liang 已提交
298
 *
T
tanek liang 已提交
299
 * \param SPI: gd32 SPI, e.g: SPI1,SPI2,SPI3.
T
tanek liang 已提交
300 301 302 303
 * \param spi_bus_name: spi bus name, e.g: "spi1"
 * \return
 *
 */
T
tanek liang 已提交
304 305
rt_err_t gd32_spi_bus_register(uint32_t spi_periph,
                            //struct gd32_spi_bus * gd32_spi,
T
tanek liang 已提交
306 307 308
                            const char * spi_bus_name)
{
    int i;
mysterywolf's avatar
mysterywolf 已提交
309

T
tanek liang 已提交
310
    RT_ASSERT(spi_bus_name != RT_NULL);
mysterywolf's avatar
mysterywolf 已提交
311

T
tanek liang 已提交
312 313 314 315 316 317
    for (i = 0; i < ARR_LEN(spis); i++)
    {
        if (spi_periph == spis[i].spi_periph)
        {
            rcu_periph_clock_enable(spis[i].spi_clk);
            spis[i].spi_bus->parent.user_data = (void *)&spis[i];
T
tanek liang 已提交
318
            rt_spi_bus_register(spis[i].spi_bus, spi_bus_name, &gd32_spi_ops);
T
tanek liang 已提交
319 320 321
            return RT_EOK;
        }
    }
mysterywolf's avatar
mysterywolf 已提交
322

T
tanek liang 已提交
323 324
    return RT_ERROR;
}
T
tanek liang 已提交
325
#endif