修正但仍有误
This commit is contained in:
@@ -1,279 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-11-16 zylx first version.
|
||||
*/
|
||||
|
||||
#include <drivers/spi.h>
|
||||
|
||||
rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg)
|
||||
{
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(cfg != RT_NULL);
|
||||
|
||||
/* reset the CS pin */
|
||||
if (device->parent.cs_pin != PIN_NONE)
|
||||
{
|
||||
if (cfg->parent.mode & RT_SPI_CS_HIGH)
|
||||
rt_pin_write(device->parent.cs_pin, PIN_LOW);
|
||||
else
|
||||
rt_pin_write(device->parent.cs_pin, PIN_HIGH);
|
||||
}
|
||||
|
||||
/* If the configurations are the same, we don't need to set again. */
|
||||
if (device->config.medium_size == cfg->medium_size &&
|
||||
device->config.ddr_mode == cfg->ddr_mode &&
|
||||
device->config.qspi_dl_width == cfg->qspi_dl_width &&
|
||||
device->config.parent.data_width == cfg->parent.data_width &&
|
||||
device->config.parent.mode == (cfg->parent.mode & RT_SPI_MODE_MASK) &&
|
||||
device->config.parent.max_hz == cfg->parent.max_hz)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* copy configuration items */
|
||||
device->config.parent.mode = cfg->parent.mode;
|
||||
device->config.parent.max_hz = cfg->parent.max_hz;
|
||||
device->config.parent.data_width = cfg->parent.data_width;
|
||||
device->config.parent.reserved = cfg->parent.reserved;
|
||||
device->config.medium_size = cfg->medium_size;
|
||||
device->config.ddr_mode = cfg->ddr_mode;
|
||||
device->config.qspi_dl_width = cfg->qspi_dl_width;
|
||||
|
||||
return rt_spi_bus_configure(&device->parent);
|
||||
}
|
||||
|
||||
rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_spi_bus_register(bus, name, ops);
|
||||
if(result == RT_EOK)
|
||||
{
|
||||
/* set SPI bus to qspi modes */
|
||||
bus->mode = RT_SPI_BUS_MODE_QSPI;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_size_t rt_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(message != RT_NULL);
|
||||
|
||||
result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_set_errno(-RT_EBUSY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reset errno */
|
||||
rt_set_errno(RT_EOK);
|
||||
|
||||
/* configure SPI bus */
|
||||
if (device->parent.bus->owner != &device->parent)
|
||||
{
|
||||
/* not the same owner as current, re-configure SPI bus */
|
||||
result = device->parent.bus->ops->configure(&device->parent, &device->parent.config);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
/* set SPI bus owner */
|
||||
device->parent.bus->owner = &device->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure SPI bus failed */
|
||||
rt_set_errno(-RT_EIO);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* transmit each SPI message */
|
||||
|
||||
result = device->parent.bus->ops->xfer(&device->parent, &message->parent);
|
||||
if (result == 0)
|
||||
{
|
||||
rt_set_errno(-RT_EIO);
|
||||
}
|
||||
|
||||
__exit:
|
||||
/* release bus lock */
|
||||
rt_mutex_release(&(device->parent.bus->lock));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length)
|
||||
{
|
||||
RT_ASSERT(send_buf);
|
||||
RT_ASSERT(recv_buf);
|
||||
RT_ASSERT(send_length != 0);
|
||||
|
||||
struct rt_qspi_message message;
|
||||
unsigned char *ptr = (unsigned char *)send_buf;
|
||||
rt_size_t count = 0;
|
||||
rt_err_t result = 0;
|
||||
|
||||
message.instruction.content = ptr[0];
|
||||
message.instruction.qspi_lines = 1;
|
||||
count++;
|
||||
|
||||
/* get address */
|
||||
if (send_length > 1)
|
||||
{
|
||||
if (device->config.medium_size > 0x1000000 && send_length >= 5)
|
||||
{
|
||||
/* medium size greater than 16Mb, address size is 4 Byte */
|
||||
message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
|
||||
message.address.size = 32;
|
||||
count += 4;
|
||||
}
|
||||
else if (send_length >= 4)
|
||||
{
|
||||
/* address size is 3 Byte */
|
||||
message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
|
||||
message.address.size = 24;
|
||||
count += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
message.address.qspi_lines = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no address stage */
|
||||
message.address.content = 0 ;
|
||||
message.address.qspi_lines = 0;
|
||||
message.address.size = 0;
|
||||
}
|
||||
|
||||
message.alternate_bytes.content = 0;
|
||||
message.alternate_bytes.size = 0;
|
||||
message.alternate_bytes.qspi_lines = 0;
|
||||
|
||||
/* set dummy cycles */
|
||||
if (count != send_length)
|
||||
{
|
||||
message.dummy_cycles = (send_length - count) * 8;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
message.dummy_cycles = 0;
|
||||
}
|
||||
|
||||
/* set recv buf and recv size */
|
||||
message.parent.recv_buf = recv_buf;
|
||||
message.parent.send_buf = RT_NULL;
|
||||
message.parent.length = recv_length;
|
||||
message.parent.cs_take = 1;
|
||||
message.parent.cs_release = 1;
|
||||
|
||||
message.qspi_data_lines = 1;
|
||||
|
||||
result = rt_qspi_transfer_message(device, &message);
|
||||
if (result == 0)
|
||||
{
|
||||
result = -RT_EIO;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = recv_length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length)
|
||||
{
|
||||
RT_ASSERT(send_buf);
|
||||
RT_ASSERT(length != 0);
|
||||
|
||||
struct rt_qspi_message message;
|
||||
unsigned char *ptr = (unsigned char *)send_buf;
|
||||
rt_size_t count = 0;
|
||||
rt_err_t result = 0;
|
||||
|
||||
message.instruction.content = ptr[0];
|
||||
message.instruction.qspi_lines = 1;
|
||||
count++;
|
||||
|
||||
/* get address */
|
||||
if (length > 1)
|
||||
{
|
||||
if (device->config.medium_size > 0x1000000 && length >= 5)
|
||||
{
|
||||
/* medium size greater than 16Mb, address size is 4 Byte */
|
||||
message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
|
||||
message.address.size = 32;
|
||||
message.address.qspi_lines = 1;
|
||||
count += 4;
|
||||
}
|
||||
else if (length >= 4)
|
||||
{
|
||||
/* address size is 3 Byte */
|
||||
message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
|
||||
message.address.size = 24;
|
||||
message.address.qspi_lines = 1;
|
||||
count += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no address stage */
|
||||
message.address.content = 0 ;
|
||||
message.address.qspi_lines = 0;
|
||||
message.address.size = 0;
|
||||
}
|
||||
|
||||
message.alternate_bytes.content = 0;
|
||||
message.alternate_bytes.size = 0;
|
||||
message.alternate_bytes.qspi_lines = 0;
|
||||
|
||||
message.dummy_cycles = 0;
|
||||
|
||||
/* determine if there is data to send */
|
||||
if (length - count > 0)
|
||||
{
|
||||
message.qspi_data_lines = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
message.qspi_data_lines = 0;
|
||||
}
|
||||
|
||||
/* set send buf and send size */
|
||||
message.parent.send_buf = ptr + count;
|
||||
message.parent.recv_buf = RT_NULL;
|
||||
message.parent.length = length - count;
|
||||
message.parent.cs_take = 1;
|
||||
message.parent.cs_release = 1;
|
||||
|
||||
result = rt_qspi_transfer_message(device, &message);
|
||||
if (result == 0)
|
||||
{
|
||||
result = -RT_EIO;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@@ -1,530 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-10-11 kyle first version
|
||||
*/
|
||||
|
||||
#include <spi-bit-ops.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "SPI"
|
||||
#ifdef RT_SPI_BITOPS_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_ERROR
|
||||
#endif
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define TOG_SCLK(ops) ops->tog_sclk(ops->data)
|
||||
#define SET_SCLK(ops, val) ops->set_sclk(ops->data, val)
|
||||
#define SET_MOSI(ops, val) ops->set_mosi(ops->data, val)
|
||||
#define SET_MISO(ops, val) ops->set_miso(ops->data, val)
|
||||
#define GET_SCLK(ops) ops->get_sclk(ops->data)
|
||||
#define GET_MOSI(ops) ops->get_mosi(ops->data)
|
||||
#define GET_MISO(ops) ops->get_miso(ops->data)
|
||||
#define DIR_MOSI(ops, val) ops->dir_mosi(ops->data, val)
|
||||
#define DIR_MISO(ops, val) ops->dir_miso(ops->data, val)
|
||||
|
||||
rt_inline void spi_delay(struct rt_spi_bit_ops *ops)
|
||||
{
|
||||
ops->udelay((ops->delay_us + 1) >> 1);
|
||||
}
|
||||
|
||||
rt_inline void spi_delay2(struct rt_spi_bit_ops *ops)
|
||||
{
|
||||
ops->udelay(ops->delay_us);
|
||||
}
|
||||
|
||||
#define SCLK_H(ops) SET_SCLK(ops, 1)
|
||||
#define SCLK_L(ops) SET_SCLK(ops, 0)
|
||||
#define MOSI_H(ops) SET_MOSI(ops, 1)
|
||||
#define MOSI_L(ops) SET_MOSI(ops, 0)
|
||||
#define MOSI_IN(ops) DIR_MOSI(ops, 1)
|
||||
#define MOSI_OUT(ops) DIR_MOSI(ops, 0)
|
||||
#define MISO_IN(ops) DIR_MISO(ops, 1)
|
||||
#define MISO_OUT(ops) DIR_MISO(ops, 0)
|
||||
|
||||
rt_inline rt_ssize_t spi_xfer_4line_data8(struct rt_spi_bit_ops *ops,
|
||||
struct rt_spi_configuration *config,
|
||||
const void *send_buf,
|
||||
void *recv_buf,
|
||||
rt_size_t length)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
RT_ASSERT(ops != RT_NULL);
|
||||
RT_ASSERT(length != 0);
|
||||
|
||||
{
|
||||
const rt_uint8_t *send_ptr = send_buf;
|
||||
rt_uint8_t *recv_ptr = recv_buf;
|
||||
rt_uint32_t size = length;
|
||||
|
||||
while (size--)
|
||||
{
|
||||
rt_uint8_t tx_data = 0xFF;
|
||||
rt_uint8_t rx_data = 0xFF;
|
||||
rt_uint8_t bit = 0;
|
||||
|
||||
if (send_buf != RT_NULL)
|
||||
{
|
||||
tx_data = *send_ptr++;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (7 - i)); }
|
||||
else { bit = tx_data & (0x1 << i); }
|
||||
|
||||
if (bit) MOSI_H(ops);
|
||||
else MOSI_L(ops);
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
TOG_SCLK(ops);
|
||||
|
||||
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x01; }
|
||||
else { rx_data >>= 1; bit = 0x80; }
|
||||
|
||||
if (GET_MISO(ops)) { rx_data |= bit; }
|
||||
else { rx_data &= ~bit; }
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 7))
|
||||
{
|
||||
TOG_SCLK(ops);
|
||||
}
|
||||
}
|
||||
|
||||
if (recv_buf != RT_NULL)
|
||||
{
|
||||
*recv_ptr++ = rx_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
rt_inline rt_ssize_t spi_xfer_4line_data16(struct rt_spi_bit_ops *ops,
|
||||
struct rt_spi_configuration *config,
|
||||
const void *send_buf,
|
||||
void *recv_buf,
|
||||
rt_size_t length)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
RT_ASSERT(ops != RT_NULL);
|
||||
RT_ASSERT(length != 0);
|
||||
|
||||
{
|
||||
const rt_uint16_t *send_ptr = send_buf;
|
||||
rt_uint16_t *recv_ptr = recv_buf;
|
||||
rt_uint32_t size = length;
|
||||
|
||||
while (size--)
|
||||
{
|
||||
rt_uint16_t tx_data = 0xFFFF;
|
||||
rt_uint16_t rx_data = 0xFFFF;
|
||||
rt_uint16_t bit = 0;
|
||||
|
||||
if (send_buf != RT_NULL)
|
||||
{
|
||||
tx_data = *send_ptr++;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (15 - i)); }
|
||||
else { bit = tx_data & (0x1 << i); }
|
||||
|
||||
if (bit) MOSI_H(ops);
|
||||
else MOSI_L(ops);
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
TOG_SCLK(ops);
|
||||
|
||||
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x0001; }
|
||||
else { rx_data >>= 1; bit = 0x8000; }
|
||||
|
||||
if (GET_MISO(ops)) { rx_data |= bit; }
|
||||
else { rx_data &= ~bit; }
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 15))
|
||||
{
|
||||
TOG_SCLK(ops);
|
||||
}
|
||||
}
|
||||
|
||||
if (recv_buf != RT_NULL)
|
||||
{
|
||||
*recv_ptr++ = rx_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
rt_inline rt_ssize_t spi_xfer_3line_data8(struct rt_spi_bit_ops *ops,
|
||||
struct rt_spi_configuration *config,
|
||||
const void *send_buf,
|
||||
void *recv_buf,
|
||||
rt_size_t length)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
RT_ASSERT(ops != RT_NULL);
|
||||
RT_ASSERT(length != 0);
|
||||
|
||||
{
|
||||
const rt_uint8_t *send_ptr = send_buf;
|
||||
rt_uint8_t *recv_ptr = recv_buf;
|
||||
rt_uint32_t size = length;
|
||||
rt_uint8_t send_flg = 0;
|
||||
|
||||
if ((send_buf != RT_NULL) || (recv_buf == RT_NULL))
|
||||
{
|
||||
MOSI_OUT(ops);
|
||||
send_flg = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
MOSI_IN(ops);
|
||||
}
|
||||
|
||||
while (size--)
|
||||
{
|
||||
rt_uint8_t tx_data = 0xFF;
|
||||
rt_uint8_t rx_data = 0xFF;
|
||||
rt_uint8_t bit = 0;
|
||||
|
||||
if (send_buf != RT_NULL)
|
||||
{
|
||||
tx_data = *send_ptr++;
|
||||
}
|
||||
|
||||
if (send_flg)
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (7 - i)); }
|
||||
else { bit = tx_data & (0x1 << i); }
|
||||
|
||||
if (bit) MOSI_H(ops);
|
||||
else MOSI_L(ops);
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
TOG_SCLK(ops);
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 7))
|
||||
{
|
||||
TOG_SCLK(ops);
|
||||
}
|
||||
}
|
||||
|
||||
rx_data = tx_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
spi_delay2(ops);
|
||||
|
||||
TOG_SCLK(ops);
|
||||
|
||||
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x01; }
|
||||
else { rx_data >>= 1; bit = 0x80; }
|
||||
|
||||
if (GET_MOSI(ops)) { rx_data |= bit; }
|
||||
else { rx_data &= ~bit; }
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 7))
|
||||
{
|
||||
TOG_SCLK(ops);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (recv_buf != RT_NULL)
|
||||
{
|
||||
*recv_ptr++ = rx_data;
|
||||
}
|
||||
}
|
||||
|
||||
if (!send_flg)
|
||||
{
|
||||
MOSI_OUT(ops);
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
rt_inline rt_ssize_t spi_xfer_3line_data16(struct rt_spi_bit_ops *ops,
|
||||
struct rt_spi_configuration *config,
|
||||
const void *send_buf,
|
||||
void *recv_buf,
|
||||
rt_size_t length)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
RT_ASSERT(ops != RT_NULL);
|
||||
RT_ASSERT(length != 0);
|
||||
|
||||
{
|
||||
const rt_uint16_t *send_ptr = send_buf;
|
||||
rt_uint16_t *recv_ptr = recv_buf;
|
||||
rt_uint32_t size = length;
|
||||
rt_uint8_t send_flg = 0;
|
||||
|
||||
if ((send_buf != RT_NULL) || (recv_buf == RT_NULL))
|
||||
{
|
||||
MOSI_OUT(ops);
|
||||
send_flg = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
MOSI_IN(ops);
|
||||
}
|
||||
|
||||
while (size--)
|
||||
{
|
||||
rt_uint16_t tx_data = 0xFFFF;
|
||||
rt_uint16_t rx_data = 0xFFFF;
|
||||
rt_uint16_t bit = 0;
|
||||
|
||||
if (send_buf != RT_NULL)
|
||||
{
|
||||
tx_data = *send_ptr++;
|
||||
}
|
||||
|
||||
if (send_flg)
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (15 - i)); }
|
||||
else { bit = tx_data & (0x1 << i); }
|
||||
|
||||
if (bit) MOSI_H(ops);
|
||||
else MOSI_L(ops);
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
TOG_SCLK(ops);
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 15))
|
||||
{
|
||||
TOG_SCLK(ops);
|
||||
}
|
||||
}
|
||||
|
||||
rx_data = tx_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
spi_delay2(ops);
|
||||
|
||||
TOG_SCLK(ops);
|
||||
|
||||
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x0001; }
|
||||
else { rx_data >>= 1; bit = 0x8000; }
|
||||
|
||||
if (GET_MOSI(ops)) { rx_data |= bit; }
|
||||
else { rx_data &= ~bit; }
|
||||
|
||||
spi_delay2(ops);
|
||||
|
||||
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 15))
|
||||
{
|
||||
TOG_SCLK(ops);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (recv_buf != RT_NULL)
|
||||
{
|
||||
*recv_ptr++ = rx_data;
|
||||
}
|
||||
}
|
||||
|
||||
if (!send_flg)
|
||||
{
|
||||
MOSI_OUT(ops);
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
rt_err_t spi_bit_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
|
||||
{
|
||||
struct rt_spi_bit_obj *obj = rt_container_of(device->bus, struct rt_spi_bit_obj, bus);
|
||||
struct rt_spi_bit_ops *ops = obj->ops;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(configuration != RT_NULL);
|
||||
|
||||
if(ops->pin_init != RT_NULL)
|
||||
{
|
||||
ops->pin_init();
|
||||
}
|
||||
|
||||
if (configuration->mode & RT_SPI_SLAVE)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
if (configuration->mode & RT_SPI_CPOL)
|
||||
{
|
||||
SCLK_H(ops);
|
||||
}
|
||||
else
|
||||
{
|
||||
SCLK_L(ops);
|
||||
}
|
||||
|
||||
if (configuration->max_hz < 200000)
|
||||
{
|
||||
ops->delay_us = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ops->delay_us = 0;
|
||||
}
|
||||
|
||||
rt_memcpy(&obj->config, configuration, sizeof(struct rt_spi_configuration));
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_ssize_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
|
||||
{
|
||||
struct rt_spi_bit_obj *obj = rt_container_of(device->bus, struct rt_spi_bit_obj, bus);
|
||||
struct rt_spi_bit_ops *ops = obj->ops;
|
||||
struct rt_spi_configuration *config = &obj->config;
|
||||
rt_base_t cs_pin = device->cs_pin;
|
||||
|
||||
RT_ASSERT(device != NULL);
|
||||
RT_ASSERT(message != NULL);
|
||||
|
||||
#ifdef RT_SPI_BITOPS_DEBUG
|
||||
if (!ops->tog_sclk || !ops->set_sclk || !ops->get_sclk)
|
||||
{
|
||||
LOG_E("SPI bus error, SCLK line not defined");
|
||||
}
|
||||
if (!ops->set_mosi || !ops->get_mosi)
|
||||
{
|
||||
LOG_E("SPI bus error, MOSI line not defined");
|
||||
}
|
||||
if (!ops->set_miso || !ops->get_miso)
|
||||
{
|
||||
LOG_E("SPI bus error, MISO line not defined");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* take CS */
|
||||
if (message->cs_take && (cs_pin != PIN_NONE))
|
||||
{
|
||||
LOG_I("spi take cs\n");
|
||||
rt_pin_write(cs_pin, PIN_LOW);
|
||||
spi_delay(ops);
|
||||
|
||||
/* spi phase */
|
||||
if (config->mode & RT_SPI_CPHA)
|
||||
{
|
||||
spi_delay(ops);
|
||||
TOG_SCLK(ops);
|
||||
}
|
||||
}
|
||||
|
||||
if (config->mode & RT_SPI_3WIRE)
|
||||
{
|
||||
if (config->data_width <= 8)
|
||||
{
|
||||
spi_xfer_3line_data8(ops,
|
||||
config,
|
||||
message->send_buf,
|
||||
message->recv_buf,
|
||||
message->length);
|
||||
}
|
||||
else if (config->data_width <= 16)
|
||||
{
|
||||
spi_xfer_3line_data16(ops,
|
||||
config,
|
||||
message->send_buf,
|
||||
message->recv_buf,
|
||||
message->length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (config->data_width <= 8)
|
||||
{
|
||||
spi_xfer_4line_data8(ops,
|
||||
config,
|
||||
message->send_buf,
|
||||
message->recv_buf,
|
||||
message->length);
|
||||
}
|
||||
else if (config->data_width <= 16)
|
||||
{
|
||||
spi_xfer_4line_data16(ops,
|
||||
config,
|
||||
message->send_buf,
|
||||
message->recv_buf,
|
||||
message->length);
|
||||
}
|
||||
}
|
||||
|
||||
/* release CS */
|
||||
if (message->cs_release && (cs_pin != PIN_NONE))
|
||||
{
|
||||
spi_delay(ops);
|
||||
rt_pin_write(cs_pin, PIN_HIGH);
|
||||
LOG_I("spi release cs\n");
|
||||
}
|
||||
|
||||
return message->length;
|
||||
}
|
||||
|
||||
static const struct rt_spi_ops spi_bit_bus_ops =
|
||||
{
|
||||
.configure = spi_bit_configure,
|
||||
.xfer = spi_bit_xfer,
|
||||
};
|
||||
|
||||
rt_err_t rt_spi_bit_add_bus(struct rt_spi_bit_obj *obj,
|
||||
const char *bus_name,
|
||||
struct rt_spi_bit_ops *ops)
|
||||
{
|
||||
obj->ops = ops;
|
||||
obj->config.data_width = 8;
|
||||
obj->config.max_hz = 1 * 1000 * 1000;
|
||||
obj->config.mode = RT_SPI_MASTER | RT_SPI_MSB | RT_SPI_MODE_0;
|
||||
|
||||
/* idle status */
|
||||
if (obj->config.mode & RT_SPI_CPOL) SCLK_H(ops);
|
||||
else SCLK_L(ops);
|
||||
|
||||
return rt_spi_bus_register(&obj->bus, bus_name, &spi_bit_bus_ops);
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-10-11 kyle first version
|
||||
* 2022-6-14 solar Remove the const attribute of private data in ops
|
||||
*/
|
||||
|
||||
#ifndef __SPI_BIT_OPS_H__
|
||||
#define __SPI_BIT_OPS_H__
|
||||
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct rt_spi_bit_ops
|
||||
{
|
||||
void *data; /* private data for lowlevel routines */
|
||||
void (*const pin_init)(void);
|
||||
void (*const tog_sclk)(void *data);
|
||||
void (*const set_sclk)(void *data, rt_int32_t state);
|
||||
void (*const set_mosi)(void *data, rt_int32_t state);
|
||||
void (*const set_miso)(void *data, rt_int32_t state);
|
||||
rt_int32_t (*const get_sclk)(void *data);
|
||||
rt_int32_t (*const get_mosi)(void *data);
|
||||
rt_int32_t (*const get_miso)(void *data);
|
||||
|
||||
void (*const dir_mosi)(void *data, rt_int32_t state);
|
||||
void (*const dir_miso)(void *data, rt_int32_t state);
|
||||
|
||||
void (*const udelay)(rt_uint32_t us);
|
||||
rt_uint32_t delay_us; /* sclk, mosi and miso line delay */
|
||||
};
|
||||
|
||||
struct rt_spi_bit_obj
|
||||
{
|
||||
struct rt_spi_bus bus;
|
||||
struct rt_spi_bit_ops *ops;
|
||||
struct rt_spi_configuration config;
|
||||
};
|
||||
|
||||
rt_err_t rt_spi_bit_add_bus(struct rt_spi_bit_obj *obj,
|
||||
const char *bus_name,
|
||||
struct rt_spi_bit_ops *ops);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -1,543 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-01-08 bernard first version.
|
||||
* 2012-02-03 bernard add const attribute to the ops.
|
||||
* 2012-05-15 dzzxzz fixed the return value in attach_device.
|
||||
* 2012-05-18 bernard Changed SPI message to message list.
|
||||
* Added take/release SPI device/bus interface.
|
||||
* 2012-09-28 aozima fixed rt_spi_release_bus assert error.
|
||||
*/
|
||||
|
||||
#include <drivers/spi.h>
|
||||
|
||||
#define DBG_TAG "spi.core"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
extern rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name);
|
||||
extern rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name);
|
||||
|
||||
rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus,
|
||||
const char *name,
|
||||
const struct rt_spi_ops *ops)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_spi_bus_device_init(bus, name);
|
||||
if (result != RT_EOK)
|
||||
return result;
|
||||
|
||||
/* initialize mutex lock */
|
||||
rt_mutex_init(&(bus->lock), name, RT_IPC_FLAG_PRIO);
|
||||
/* set ops */
|
||||
bus->ops = ops;
|
||||
/* initialize owner */
|
||||
bus->owner = RT_NULL;
|
||||
/* set bus mode */
|
||||
bus->mode = RT_SPI_BUS_MODE_SPI;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_bus_attach_device_cspin(struct rt_spi_device *device,
|
||||
const char *name,
|
||||
const char *bus_name,
|
||||
rt_base_t cs_pin,
|
||||
void *user_data)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_device_t bus;
|
||||
|
||||
/* get physical spi bus */
|
||||
bus = rt_device_find(bus_name);
|
||||
if (bus != RT_NULL && bus->type == RT_Device_Class_SPIBUS)
|
||||
{
|
||||
device->bus = (struct rt_spi_bus *)bus;
|
||||
|
||||
/* initialize spidev device */
|
||||
result = rt_spidev_device_init(device, name);
|
||||
if (result != RT_EOK)
|
||||
return result;
|
||||
|
||||
if(cs_pin != PIN_NONE)
|
||||
{
|
||||
rt_pin_mode(cs_pin, PIN_MODE_OUTPUT);
|
||||
}
|
||||
|
||||
rt_memset(&device->config, 0, sizeof(device->config));
|
||||
device->parent.user_data = user_data;
|
||||
device->cs_pin = cs_pin;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* not found the host bus */
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_bus_attach_device(struct rt_spi_device *device,
|
||||
const char *name,
|
||||
const char *bus_name,
|
||||
void *user_data)
|
||||
{
|
||||
return rt_spi_bus_attach_device_cspin(device, name, bus_name, PIN_NONE, user_data);
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_bus_configure(struct rt_spi_device *device)
|
||||
{
|
||||
rt_err_t result = -RT_ERROR;
|
||||
|
||||
if (device->bus != RT_NULL)
|
||||
{
|
||||
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
if (device->bus->owner == device)
|
||||
{
|
||||
/* current device is using, re-configure SPI bus */
|
||||
result = device->bus->ops->configure(device, &device->config);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
/* configure SPI bus failed */
|
||||
LOG_E("SPI device %s configuration failed", device->parent.parent.name);
|
||||
}
|
||||
}
|
||||
|
||||
/* release lock */
|
||||
rt_mutex_release(&(device->bus->lock));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = RT_EOK;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_configure(struct rt_spi_device *device,
|
||||
struct rt_spi_configuration *cfg)
|
||||
{
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(cfg != RT_NULL);
|
||||
|
||||
/* reset the CS pin */
|
||||
if (device->cs_pin != PIN_NONE)
|
||||
{
|
||||
if (cfg->mode & RT_SPI_CS_HIGH)
|
||||
rt_pin_write(device->cs_pin, PIN_LOW);
|
||||
else
|
||||
rt_pin_write(device->cs_pin, PIN_HIGH);
|
||||
}
|
||||
|
||||
/* If the configurations are the same, we don't need to set again. */
|
||||
if (device->config.data_width == cfg->data_width &&
|
||||
device->config.mode == (cfg->mode & RT_SPI_MODE_MASK) &&
|
||||
device->config.max_hz == cfg->max_hz)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* set configuration */
|
||||
device->config.data_width = cfg->data_width;
|
||||
device->config.mode = cfg->mode & RT_SPI_MODE_MASK;
|
||||
device->config.max_hz = cfg->max_hz;
|
||||
|
||||
return rt_spi_bus_configure(device);
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
|
||||
const void *send_buf1,
|
||||
rt_size_t send_length1,
|
||||
const void *send_buf2,
|
||||
rt_size_t send_length2)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct rt_spi_message message;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
|
||||
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
if (device->bus->owner != device)
|
||||
{
|
||||
/* not the same owner as current, re-configure SPI bus */
|
||||
result = device->bus->ops->configure(device, &device->config);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
/* set SPI bus owner */
|
||||
device->bus->owner = device;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure SPI bus failed */
|
||||
LOG_E("SPI device %s configuration failed", device->parent.parent.name);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* send data1 */
|
||||
message.send_buf = send_buf1;
|
||||
message.recv_buf = RT_NULL;
|
||||
message.length = send_length1;
|
||||
message.cs_take = 1;
|
||||
message.cs_release = 0;
|
||||
message.next = RT_NULL;
|
||||
|
||||
result = device->bus->ops->xfer(device, &message);
|
||||
if (result < 0)
|
||||
{
|
||||
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* send data2 */
|
||||
message.send_buf = send_buf2;
|
||||
message.recv_buf = RT_NULL;
|
||||
message.length = send_length2;
|
||||
message.cs_take = 0;
|
||||
message.cs_release = 1;
|
||||
message.next = RT_NULL;
|
||||
|
||||
result = device->bus->ops->xfer(device, &message);
|
||||
if (result < 0)
|
||||
{
|
||||
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
result = RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
__exit:
|
||||
rt_mutex_release(&(device->bus->lock));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
|
||||
const void *send_buf,
|
||||
rt_size_t send_length,
|
||||
void *recv_buf,
|
||||
rt_size_t recv_length)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct rt_spi_message message;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
|
||||
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
if (device->bus->owner != device)
|
||||
{
|
||||
/* not the same owner as current, re-configure SPI bus */
|
||||
result = device->bus->ops->configure(device, &device->config);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
/* set SPI bus owner */
|
||||
device->bus->owner = device;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure SPI bus failed */
|
||||
LOG_E("SPI device %s configuration failed", device->parent.parent.name);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* send data */
|
||||
message.send_buf = send_buf;
|
||||
message.recv_buf = RT_NULL;
|
||||
message.length = send_length;
|
||||
message.cs_take = 1;
|
||||
message.cs_release = 0;
|
||||
message.next = RT_NULL;
|
||||
|
||||
result = device->bus->ops->xfer(device, &message);
|
||||
if (result < 0)
|
||||
{
|
||||
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* recv data */
|
||||
message.send_buf = RT_NULL;
|
||||
message.recv_buf = recv_buf;
|
||||
message.length = recv_length;
|
||||
message.cs_take = 0;
|
||||
message.cs_release = 1;
|
||||
message.next = RT_NULL;
|
||||
|
||||
result = device->bus->ops->xfer(device, &message);
|
||||
if (result < 0)
|
||||
{
|
||||
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
result = RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
__exit:
|
||||
rt_mutex_release(&(device->bus->lock));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_ssize_t rt_spi_transfer(struct rt_spi_device *device,
|
||||
const void *send_buf,
|
||||
void *recv_buf,
|
||||
rt_size_t length)
|
||||
{
|
||||
rt_ssize_t result;
|
||||
struct rt_spi_message message;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
|
||||
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
if (device->bus->owner != device)
|
||||
{
|
||||
/* not the same owner as current, re-configure SPI bus */
|
||||
result = device->bus->ops->configure(device, &device->config);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
/* set SPI bus owner */
|
||||
device->bus->owner = device;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure SPI bus failed */
|
||||
LOG_E("SPI device %s configuration failed", device->parent.parent.name);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* initial message */
|
||||
message.send_buf = send_buf;
|
||||
message.recv_buf = recv_buf;
|
||||
message.length = length;
|
||||
message.cs_take = 1;
|
||||
message.cs_release = 1;
|
||||
message.next = RT_NULL;
|
||||
|
||||
/* transfer message */
|
||||
result = device->bus->ops->xfer(device, &message);
|
||||
if (result < 0)
|
||||
{
|
||||
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
__exit:
|
||||
rt_mutex_release(&(device->bus->lock));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_sendrecv8(struct rt_spi_device *device,
|
||||
rt_uint8_t senddata,
|
||||
rt_uint8_t *recvdata)
|
||||
{
|
||||
rt_ssize_t len = rt_spi_transfer(device, &senddata, recvdata, 1);
|
||||
if (len < 0)
|
||||
{
|
||||
return (rt_err_t)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_sendrecv16(struct rt_spi_device *device,
|
||||
rt_uint16_t senddata,
|
||||
rt_uint16_t *recvdata)
|
||||
{
|
||||
rt_ssize_t len;
|
||||
rt_uint16_t tmp;
|
||||
|
||||
if (device->config.mode & RT_SPI_MSB)
|
||||
{
|
||||
tmp = ((senddata & 0xff00) >> 8) | ((senddata & 0x00ff) << 8);
|
||||
senddata = tmp;
|
||||
}
|
||||
|
||||
len = rt_spi_transfer(device, &senddata, recvdata, 2);
|
||||
if(len < 0)
|
||||
{
|
||||
return (rt_err_t)len;
|
||||
}
|
||||
|
||||
if (device->config.mode & RT_SPI_MSB)
|
||||
{
|
||||
tmp = ((*recvdata & 0xff00) >> 8) | ((*recvdata & 0x00ff) << 8);
|
||||
*recvdata = tmp;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device *device,
|
||||
struct rt_spi_message *message)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct rt_spi_message *index;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
|
||||
/* get first message */
|
||||
index = message;
|
||||
if (index == RT_NULL)
|
||||
return index;
|
||||
|
||||
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* configure SPI bus */
|
||||
if (device->bus->owner != device)
|
||||
{
|
||||
/* not the same owner as current, re-configure SPI bus */
|
||||
result = device->bus->ops->configure(device, &device->config);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
/* set SPI bus owner */
|
||||
device->bus->owner = device;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure SPI bus failed */
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* transmit each SPI message */
|
||||
while (index != RT_NULL)
|
||||
{
|
||||
/* transmit SPI message */
|
||||
result = device->bus->ops->xfer(device, index);
|
||||
if (result < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
index = index->next;
|
||||
}
|
||||
|
||||
__exit:
|
||||
/* release bus lock */
|
||||
rt_mutex_release(&(device->bus->lock));
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_take_bus(struct rt_spi_device *device)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
|
||||
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return -RT_EBUSY;
|
||||
}
|
||||
|
||||
/* configure SPI bus */
|
||||
if (device->bus->owner != device)
|
||||
{
|
||||
/* not the same owner as current, re-configure SPI bus */
|
||||
result = device->bus->ops->configure(device, &device->config);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
/* set SPI bus owner */
|
||||
device->bus->owner = device;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure SPI bus failed */
|
||||
rt_mutex_release(&(device->bus->lock));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_release_bus(struct rt_spi_device *device)
|
||||
{
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
RT_ASSERT(device->bus->owner == device);
|
||||
|
||||
/* release lock */
|
||||
return rt_mutex_release(&(device->bus->lock));
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_take(struct rt_spi_device *device)
|
||||
{
|
||||
rt_ssize_t result;
|
||||
struct rt_spi_message message;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
|
||||
rt_memset(&message, 0, sizeof(message));
|
||||
message.cs_take = 1;
|
||||
|
||||
result = device->bus->ops->xfer(device, &message);
|
||||
if(result < 0)
|
||||
{
|
||||
return (rt_err_t)result;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_spi_release(struct rt_spi_device *device)
|
||||
{
|
||||
rt_ssize_t result;
|
||||
struct rt_spi_message message;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
|
||||
rt_memset(&message, 0, sizeof(message));
|
||||
message.cs_release = 1;
|
||||
|
||||
result = device->bus->ops->xfer(device, &message);
|
||||
if(result < 0)
|
||||
{
|
||||
return (rt_err_t)result;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <drivers/spi.h>
|
||||
|
||||
/* SPI bus device interface, compatible with RT-Thread 0.3.x/1.0.x */
|
||||
static rt_ssize_t _spi_bus_device_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
struct rt_spi_bus *bus;
|
||||
|
||||
bus = (struct rt_spi_bus *)dev;
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
RT_ASSERT(bus->owner != RT_NULL);
|
||||
|
||||
return rt_spi_transfer(bus->owner, RT_NULL, buffer, size);
|
||||
}
|
||||
|
||||
static rt_ssize_t _spi_bus_device_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
struct rt_spi_bus *bus;
|
||||
|
||||
bus = (struct rt_spi_bus *)dev;
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
RT_ASSERT(bus->owner != RT_NULL);
|
||||
|
||||
return rt_spi_transfer(bus->owner, buffer, RT_NULL, size);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops spi_bus_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
_spi_bus_device_read,
|
||||
_spi_bus_device_write,
|
||||
RT_NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name)
|
||||
{
|
||||
struct rt_device *device;
|
||||
RT_ASSERT(bus != RT_NULL);
|
||||
|
||||
device = &bus->parent;
|
||||
|
||||
/* set device type */
|
||||
device->type = RT_Device_Class_SPIBUS;
|
||||
/* initialize device interface */
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &spi_bus_ops;
|
||||
#else
|
||||
device->init = RT_NULL;
|
||||
device->open = RT_NULL;
|
||||
device->close = RT_NULL;
|
||||
device->read = _spi_bus_device_read;
|
||||
device->write = _spi_bus_device_write;
|
||||
device->control = RT_NULL;
|
||||
#endif
|
||||
|
||||
/* register to device manager */
|
||||
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
|
||||
}
|
||||
|
||||
/* SPI Dev device interface, compatible with RT-Thread 0.3.x/1.0.x */
|
||||
static rt_ssize_t _spidev_device_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
struct rt_spi_device *device;
|
||||
|
||||
device = (struct rt_spi_device *)dev;
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
|
||||
return rt_spi_transfer(device, RT_NULL, buffer, size);
|
||||
}
|
||||
|
||||
static rt_ssize_t _spidev_device_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
struct rt_spi_device *device;
|
||||
|
||||
device = (struct rt_spi_device *)dev;
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
|
||||
return rt_spi_transfer(device, buffer, RT_NULL, size);
|
||||
}
|
||||
|
||||
static rt_err_t _spidev_device_control(rt_device_t dev,
|
||||
int cmd,
|
||||
void *args)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case 0: /* set device */
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops spi_device_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
_spidev_device_read,
|
||||
_spidev_device_write,
|
||||
_spidev_device_control
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name)
|
||||
{
|
||||
struct rt_device *device;
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
device = &(dev->parent);
|
||||
|
||||
/* set device type */
|
||||
device->type = RT_Device_Class_SPIDevice;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &spi_device_ops;
|
||||
#else
|
||||
device->init = RT_NULL;
|
||||
device->open = RT_NULL;
|
||||
device->close = RT_NULL;
|
||||
device->read = _spidev_device_read;
|
||||
device->write = _spidev_device_write;
|
||||
device->control = _spidev_device_control;
|
||||
#endif
|
||||
|
||||
/* register to device manager */
|
||||
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016/5/20 bernard the first version
|
||||
* 2020/1/7 redoc add include
|
||||
*/
|
||||
|
||||
#ifndef SPI_FLASH_H__
|
||||
#define SPI_FLASH_H__
|
||||
|
||||
#include <rtdevice.h>
|
||||
|
||||
struct spi_flash_device
|
||||
{
|
||||
struct rt_device flash_device;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
struct rt_spi_device * rt_spi_device;
|
||||
struct rt_mutex lock;
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
typedef struct spi_flash_device *rt_spi_flash_device_t;
|
||||
|
||||
#ifdef RT_USING_MTD_NOR
|
||||
struct spi_flash_mtd
|
||||
{
|
||||
struct rt_mtd_nor_device mtd_device;
|
||||
struct rt_spi_device * rt_spi_device;
|
||||
struct rt_mutex lock;
|
||||
void * user_data;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -1,779 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016-09-28 armink first version.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <rtdevice.h>
|
||||
#include "spi_flash.h"
|
||||
#include "spi_flash_sfud.h"
|
||||
|
||||
#ifdef RT_USING_SFUD
|
||||
|
||||
#ifndef RT_SFUD_DEFAULT_SPI_CFG
|
||||
|
||||
#ifndef RT_SFUD_SPI_MAX_HZ
|
||||
#define RT_SFUD_SPI_MAX_HZ 50000000
|
||||
#endif
|
||||
|
||||
/* read the JEDEC SFDP command must run at 50 MHz or less */
|
||||
#define RT_SFUD_DEFAULT_SPI_CFG \
|
||||
{ \
|
||||
.mode = RT_SPI_MODE_0 | RT_SPI_MSB, \
|
||||
.data_width = 8, \
|
||||
.max_hz = RT_SFUD_SPI_MAX_HZ, \
|
||||
}
|
||||
#endif /* RT_SFUD_DEFAULT_SPI_CFG */
|
||||
|
||||
#ifdef SFUD_USING_QSPI
|
||||
#define RT_SFUD_DEFAULT_QSPI_CFG \
|
||||
{ \
|
||||
RT_SFUD_DEFAULT_SPI_CFG, \
|
||||
.medium_size = 0x800000, \
|
||||
.ddr_mode = 0, \
|
||||
.qspi_dl_width = 4, \
|
||||
}
|
||||
#endif /* SFUD_USING_QSPI */
|
||||
|
||||
static rt_err_t rt_sfud_control(rt_device_t dev, int cmd, void *args) {
|
||||
RT_ASSERT(dev);
|
||||
|
||||
switch (cmd) {
|
||||
case RT_DEVICE_CTRL_BLK_GETGEOME: {
|
||||
struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *) args;
|
||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
|
||||
|
||||
if (rtt_dev == RT_NULL || geometry == RT_NULL) {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
geometry->bytes_per_sector = rtt_dev->geometry.bytes_per_sector;
|
||||
geometry->sector_count = rtt_dev->geometry.sector_count;
|
||||
geometry->block_size = rtt_dev->geometry.block_size;
|
||||
break;
|
||||
}
|
||||
case RT_DEVICE_CTRL_BLK_ERASE: {
|
||||
rt_uint32_t *addrs = (rt_uint32_t *) args, start_addr = addrs[0], end_addr = addrs[1], phy_start_addr;
|
||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
|
||||
sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
|
||||
rt_size_t phy_size;
|
||||
|
||||
if (addrs == RT_NULL || start_addr > end_addr || rtt_dev == RT_NULL || sfud_dev == RT_NULL) {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (end_addr == start_addr) {
|
||||
end_addr ++;
|
||||
}
|
||||
|
||||
phy_start_addr = start_addr * rtt_dev->geometry.bytes_per_sector;
|
||||
phy_size = (end_addr - start_addr) * rtt_dev->geometry.bytes_per_sector;
|
||||
|
||||
if (sfud_erase(sfud_dev, phy_start_addr, phy_size) != SFUD_SUCCESS) {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
||||
static rt_ssize_t rt_sfud_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) {
|
||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
|
||||
sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
|
||||
|
||||
RT_ASSERT(dev);
|
||||
RT_ASSERT(rtt_dev);
|
||||
RT_ASSERT(sfud_dev);
|
||||
/* change the block device's logic address to physical address */
|
||||
rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
|
||||
rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
|
||||
|
||||
if (sfud_read(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
|
||||
return 0;
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_sfud_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) {
|
||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
|
||||
sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
|
||||
|
||||
RT_ASSERT(dev);
|
||||
RT_ASSERT(rtt_dev);
|
||||
RT_ASSERT(sfud_dev);
|
||||
/* change the block device's logic address to physical address */
|
||||
rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
|
||||
rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
|
||||
|
||||
if (sfud_erase_write(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
|
||||
return 0;
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SPI write data then read data
|
||||
*/
|
||||
static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
|
||||
size_t read_size) {
|
||||
sfud_err result = SFUD_SUCCESS;
|
||||
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
|
||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
|
||||
|
||||
RT_ASSERT(spi);
|
||||
RT_ASSERT(sfud_dev);
|
||||
RT_ASSERT(rtt_dev);
|
||||
#ifdef SFUD_USING_QSPI
|
||||
struct rt_qspi_device *qspi_dev = RT_NULL;
|
||||
#endif
|
||||
if (write_size) {
|
||||
RT_ASSERT(write_buf);
|
||||
}
|
||||
if (read_size) {
|
||||
RT_ASSERT(read_buf);
|
||||
}
|
||||
#ifdef SFUD_USING_QSPI
|
||||
if(rtt_dev->rt_spi_device->bus->mode & RT_SPI_BUS_MODE_QSPI) {
|
||||
qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
|
||||
if (write_size && read_size) {
|
||||
if (rt_qspi_send_then_recv(qspi_dev, write_buf, write_size, read_buf, read_size) <= 0) {
|
||||
result = SFUD_ERR_TIMEOUT;
|
||||
}
|
||||
} else if (write_size) {
|
||||
if (rt_qspi_send(qspi_dev, write_buf, write_size) <= 0) {
|
||||
result = SFUD_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (write_size && read_size) {
|
||||
if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
|
||||
result = SFUD_ERR_TIMEOUT;
|
||||
}
|
||||
} else if (write_size) {
|
||||
if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) <= 0) {
|
||||
result = SFUD_ERR_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) <= 0) {
|
||||
result = SFUD_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef SFUD_USING_QSPI
|
||||
/**
|
||||
* QSPI fast read data
|
||||
*/
|
||||
static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format, uint8_t *read_buf, size_t read_size) {
|
||||
struct rt_qspi_message message;
|
||||
sfud_err result = SFUD_SUCCESS;
|
||||
|
||||
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
|
||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
|
||||
struct rt_qspi_device *qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
|
||||
|
||||
RT_ASSERT(spi);
|
||||
RT_ASSERT(sfud_dev);
|
||||
RT_ASSERT(rtt_dev);
|
||||
RT_ASSERT(qspi_dev);
|
||||
|
||||
/* set message struct */
|
||||
message.instruction.content = qspi_read_cmd_format->instruction;
|
||||
message.instruction.qspi_lines = qspi_read_cmd_format->instruction_lines;
|
||||
|
||||
message.address.content = addr;
|
||||
message.address.size = qspi_read_cmd_format->address_size;
|
||||
message.address.qspi_lines = qspi_read_cmd_format->address_lines;
|
||||
|
||||
message.alternate_bytes.content = 0;
|
||||
message.alternate_bytes.size = 0;
|
||||
message.alternate_bytes.qspi_lines = 0;
|
||||
|
||||
message.dummy_cycles = qspi_read_cmd_format->dummy_cycles;
|
||||
|
||||
message.parent.send_buf = RT_NULL;
|
||||
message.parent.recv_buf = read_buf;
|
||||
message.parent.length = read_size;
|
||||
message.parent.cs_release = 1;
|
||||
message.parent.cs_take = 1;
|
||||
message.qspi_data_lines = qspi_read_cmd_format->data_lines;
|
||||
|
||||
if (rt_qspi_transfer_message(qspi_dev, &message) != read_size) {
|
||||
result = SFUD_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void spi_lock(const sfud_spi *spi) {
|
||||
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
|
||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
|
||||
|
||||
RT_ASSERT(spi);
|
||||
RT_ASSERT(sfud_dev);
|
||||
RT_ASSERT(rtt_dev);
|
||||
|
||||
rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
static void spi_unlock(const sfud_spi *spi) {
|
||||
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
|
||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
|
||||
|
||||
RT_ASSERT(spi);
|
||||
RT_ASSERT(sfud_dev);
|
||||
RT_ASSERT(rtt_dev);
|
||||
|
||||
rt_mutex_release(&(rtt_dev->lock));
|
||||
}
|
||||
|
||||
static void retry_delay_100us(void) {
|
||||
/* 100 microsecond delay */
|
||||
rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
|
||||
}
|
||||
|
||||
sfud_err sfud_spi_port_init(sfud_flash *flash) {
|
||||
sfud_err result = SFUD_SUCCESS;
|
||||
|
||||
RT_ASSERT(flash);
|
||||
|
||||
/* port SPI device interface */
|
||||
flash->spi.wr = spi_write_read;
|
||||
#ifdef SFUD_USING_QSPI
|
||||
flash->spi.qspi_read = qspi_read;
|
||||
#endif
|
||||
flash->spi.lock = spi_lock;
|
||||
flash->spi.unlock = spi_unlock;
|
||||
flash->spi.user_data = flash;
|
||||
if (RT_TICK_PER_SECOND < 1000) {
|
||||
LOG_W("[SFUD] Warning: The OS tick(%d) is less than 1000. So the flash write will take more time.", RT_TICK_PER_SECOND);
|
||||
}
|
||||
/* 100 microsecond delay */
|
||||
flash->retry.delay = retry_delay_100us;
|
||||
/* 60 seconds timeout */
|
||||
flash->retry.times = 60 * 10000;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops flash_device_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
rt_sfud_read,
|
||||
rt_sfud_write,
|
||||
rt_sfud_control
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Probe SPI flash by SFUD (Serial Flash Universal Driver) driver library and though SPI device by specified configuration.
|
||||
*
|
||||
* @param spi_flash_dev_name the name which will create SPI flash device
|
||||
* @param spi_dev_name using SPI device name
|
||||
* @param spi_cfg SPI device configuration
|
||||
* @param qspi_cfg QSPI device configuration
|
||||
*
|
||||
* @return probed SPI flash device, probe failed will return RT_NULL
|
||||
*/
|
||||
rt_spi_flash_device_t rt_sfud_flash_probe_ex(const char *spi_flash_dev_name, const char *spi_dev_name,
|
||||
struct rt_spi_configuration *spi_cfg, struct rt_qspi_configuration *qspi_cfg)
|
||||
{
|
||||
rt_spi_flash_device_t rtt_dev = RT_NULL;
|
||||
sfud_flash *sfud_dev = RT_NULL;
|
||||
char *spi_flash_dev_name_bak = RT_NULL, *spi_dev_name_bak = RT_NULL;
|
||||
extern sfud_err sfud_device_init(sfud_flash *flash);
|
||||
#ifdef SFUD_USING_QSPI
|
||||
struct rt_qspi_device *qspi_dev = RT_NULL;
|
||||
#endif
|
||||
|
||||
RT_ASSERT(spi_flash_dev_name);
|
||||
RT_ASSERT(spi_dev_name);
|
||||
|
||||
rtt_dev = (rt_spi_flash_device_t) rt_malloc(sizeof(struct spi_flash_device));
|
||||
sfud_dev = (sfud_flash_t) rt_malloc(sizeof(sfud_flash));
|
||||
spi_flash_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_flash_dev_name) + 1);
|
||||
spi_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_dev_name) + 1);
|
||||
|
||||
if (rtt_dev) {
|
||||
rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device));
|
||||
/* initialize lock */
|
||||
rt_mutex_init(&(rtt_dev->lock), spi_flash_dev_name, RT_IPC_FLAG_PRIO);
|
||||
}
|
||||
|
||||
if (rtt_dev && sfud_dev && spi_flash_dev_name_bak && spi_dev_name_bak) {
|
||||
rt_memset(sfud_dev, 0, sizeof(sfud_flash));
|
||||
rt_strncpy(spi_flash_dev_name_bak, spi_flash_dev_name, rt_strlen(spi_flash_dev_name));
|
||||
rt_strncpy(spi_dev_name_bak, spi_dev_name, rt_strlen(spi_dev_name));
|
||||
/* make string end sign */
|
||||
spi_flash_dev_name_bak[rt_strlen(spi_flash_dev_name)] = '\0';
|
||||
spi_dev_name_bak[rt_strlen(spi_dev_name)] = '\0';
|
||||
/* SPI configure */
|
||||
{
|
||||
/* RT-Thread SPI device initialize */
|
||||
rtt_dev->rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
|
||||
if (rtt_dev->rt_spi_device == RT_NULL || rtt_dev->rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {
|
||||
LOG_E("ERROR: SPI device %s not found!", spi_dev_name);
|
||||
goto error;
|
||||
}
|
||||
sfud_dev->spi.name = spi_dev_name_bak;
|
||||
|
||||
#ifdef SFUD_USING_QSPI
|
||||
/* set the qspi line number and configure the QSPI bus */
|
||||
if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
|
||||
qspi_dev = (struct rt_qspi_device *)rtt_dev->rt_spi_device;
|
||||
qspi_cfg->qspi_dl_width = qspi_dev->config.qspi_dl_width;
|
||||
rt_qspi_configure(qspi_dev, qspi_cfg);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
rt_spi_configure(rtt_dev->rt_spi_device, spi_cfg);
|
||||
}
|
||||
/* SFUD flash device initialize */
|
||||
{
|
||||
sfud_dev->name = spi_flash_dev_name_bak;
|
||||
/* accessed each other */
|
||||
rtt_dev->user_data = sfud_dev;
|
||||
rtt_dev->rt_spi_device->user_data = rtt_dev;
|
||||
rtt_dev->flash_device.user_data = rtt_dev;
|
||||
sfud_dev->user_data = rtt_dev;
|
||||
/* initialize SFUD device */
|
||||
if (sfud_device_init(sfud_dev) != SFUD_SUCCESS) {
|
||||
LOG_E("ERROR: SPI flash probe failed by SPI device %s.", spi_dev_name);
|
||||
goto error;
|
||||
}
|
||||
/* when initialize success, then copy SFUD flash device's geometry to RT-Thread SPI flash device */
|
||||
rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
|
||||
rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
|
||||
rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
|
||||
#ifdef SFUD_USING_QSPI
|
||||
/* reconfigure the QSPI bus for medium size */
|
||||
if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
|
||||
qspi_cfg->medium_size = sfud_dev->chip.capacity;
|
||||
rt_qspi_configure(qspi_dev, qspi_cfg);
|
||||
if(qspi_dev->enter_qspi_mode != RT_NULL)
|
||||
qspi_dev->enter_qspi_mode(qspi_dev);
|
||||
|
||||
/* set data lines width */
|
||||
sfud_qspi_fast_read_enable(sfud_dev, qspi_dev->config.qspi_dl_width);
|
||||
}
|
||||
#endif /* SFUD_USING_QSPI */
|
||||
}
|
||||
|
||||
/* register device */
|
||||
rtt_dev->flash_device.type = RT_Device_Class_Block;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
rtt_dev->flash_device.ops = &flash_device_ops;
|
||||
#else
|
||||
rtt_dev->flash_device.init = RT_NULL;
|
||||
rtt_dev->flash_device.open = RT_NULL;
|
||||
rtt_dev->flash_device.close = RT_NULL;
|
||||
rtt_dev->flash_device.read = rt_sfud_read;
|
||||
rtt_dev->flash_device.write = rt_sfud_write;
|
||||
rtt_dev->flash_device.control = rt_sfud_control;
|
||||
#endif
|
||||
|
||||
rt_device_register(&(rtt_dev->flash_device), spi_flash_dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
|
||||
|
||||
LOG_I("Probe SPI flash %s by SPI device %s success.",spi_flash_dev_name, spi_dev_name);
|
||||
return rtt_dev;
|
||||
} else {
|
||||
LOG_E("ERROR: Low memory.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
if (rtt_dev) {
|
||||
rt_mutex_detach(&(rtt_dev->lock));
|
||||
}
|
||||
/* may be one of objects memory was malloc success, so need free all */
|
||||
rt_free(rtt_dev);
|
||||
rt_free(sfud_dev);
|
||||
rt_free(spi_flash_dev_name_bak);
|
||||
rt_free(spi_dev_name_bak);
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
|
||||
*
|
||||
* @param spi_flash_dev_name the name which will create SPI flash device
|
||||
* @param spi_dev_name using SPI device name
|
||||
*
|
||||
* @return probed SPI flash device, probe failed will return RT_NULL
|
||||
*/
|
||||
rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name)
|
||||
{
|
||||
struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
|
||||
#ifndef SFUD_USING_QSPI
|
||||
return rt_sfud_flash_probe_ex(spi_flash_dev_name, spi_dev_name, &cfg, RT_NULL);
|
||||
#else
|
||||
struct rt_qspi_configuration qspi_cfg = RT_SFUD_DEFAULT_QSPI_CFG;
|
||||
|
||||
return rt_sfud_flash_probe_ex(spi_flash_dev_name, spi_dev_name, &cfg, &qspi_cfg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete SPI flash device
|
||||
*
|
||||
* @param spi_flash_dev SPI flash device
|
||||
*
|
||||
* @return the operation status, RT_EOK on successful
|
||||
*/
|
||||
rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev) {
|
||||
sfud_flash *sfud_flash_dev = (sfud_flash *) (spi_flash_dev->user_data);
|
||||
|
||||
RT_ASSERT(spi_flash_dev);
|
||||
RT_ASSERT(sfud_flash_dev);
|
||||
|
||||
rt_device_unregister(&(spi_flash_dev->flash_device));
|
||||
|
||||
rt_mutex_detach(&(spi_flash_dev->lock));
|
||||
|
||||
rt_free(sfud_flash_dev->spi.name);
|
||||
rt_free(sfud_flash_dev->name);
|
||||
rt_free(sfud_flash_dev);
|
||||
rt_free(spi_flash_dev);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
sfud_flash_t rt_sfud_flash_find(const char *spi_dev_name)
|
||||
{
|
||||
rt_spi_flash_device_t rtt_dev = RT_NULL;
|
||||
struct rt_spi_device *rt_spi_device = RT_NULL;
|
||||
sfud_flash_t sfud_dev = RT_NULL;
|
||||
|
||||
rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
|
||||
if (rt_spi_device == RT_NULL || rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {
|
||||
LOG_E("ERROR: SPI device %s not found!", spi_dev_name);
|
||||
goto __error;
|
||||
}
|
||||
|
||||
rtt_dev = (rt_spi_flash_device_t) (rt_spi_device->user_data);
|
||||
if (rtt_dev && rtt_dev->user_data) {
|
||||
sfud_dev = (sfud_flash_t) (rtt_dev->user_data);
|
||||
return sfud_dev;
|
||||
} else {
|
||||
LOG_E("ERROR: SFUD flash device not found!");
|
||||
goto __error;
|
||||
}
|
||||
|
||||
__error:
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
sfud_flash_t rt_sfud_flash_find_by_dev_name(const char *flash_dev_name)
|
||||
{
|
||||
rt_spi_flash_device_t rtt_dev = RT_NULL;
|
||||
sfud_flash_t sfud_dev = RT_NULL;
|
||||
|
||||
rtt_dev = (rt_spi_flash_device_t) rt_device_find(flash_dev_name);
|
||||
if (rtt_dev == RT_NULL || rtt_dev->flash_device.type != RT_Device_Class_Block) {
|
||||
LOG_E("ERROR: Flash device %s not found!", flash_dev_name);
|
||||
goto __error;
|
||||
}
|
||||
|
||||
if (rtt_dev->user_data) {
|
||||
sfud_dev = (sfud_flash_t) (rtt_dev->user_data);
|
||||
return sfud_dev;
|
||||
} else {
|
||||
LOG_E("ERROR: SFUD flash device not found!");
|
||||
goto __error;
|
||||
}
|
||||
|
||||
__error:
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_FINSH)
|
||||
|
||||
#include <finsh.h>
|
||||
|
||||
static void sf(uint8_t argc, char **argv) {
|
||||
|
||||
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
|
||||
#define HEXDUMP_WIDTH 16
|
||||
#define CMD_PROBE_INDEX 0
|
||||
#define CMD_READ_INDEX 1
|
||||
#define CMD_WRITE_INDEX 2
|
||||
#define CMD_ERASE_INDEX 3
|
||||
#define CMD_RW_STATUS_INDEX 4
|
||||
#define CMD_BENCH_INDEX 5
|
||||
|
||||
sfud_err result = SFUD_SUCCESS;
|
||||
static const sfud_flash *sfud_dev = NULL;
|
||||
static rt_spi_flash_device_t rtt_dev = NULL, rtt_dev_bak = NULL;
|
||||
size_t i = 0, j = 0;
|
||||
|
||||
const char* sf_help_info[] = {
|
||||
[CMD_PROBE_INDEX] = "sf probe [spi_device] - probe and init SPI flash by given 'spi_device'",
|
||||
[CMD_READ_INDEX] = "sf read addr size - read 'size' bytes starting at 'addr'",
|
||||
[CMD_WRITE_INDEX] = "sf write addr data1 ... dataN - write some bytes 'data' to flash starting at 'addr'",
|
||||
[CMD_ERASE_INDEX] = "sf erase addr size - erase 'size' bytes starting at 'addr'",
|
||||
[CMD_RW_STATUS_INDEX] = "sf status [<volatile> <status>] - read or write '1:volatile|0:non-volatile' 'status'",
|
||||
[CMD_BENCH_INDEX] = "sf bench - full chip benchmark. DANGER: It will erase full chip!",
|
||||
};
|
||||
|
||||
if (argc < 2) {
|
||||
rt_kprintf("Usage:\n");
|
||||
for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
|
||||
rt_kprintf("%s\n", sf_help_info[i]);
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
} else {
|
||||
const char *operator = argv[1];
|
||||
uint32_t addr, size;
|
||||
|
||||
if (!strcmp(operator, "probe")) {
|
||||
if (argc < 3) {
|
||||
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_PROBE_INDEX]);
|
||||
} else {
|
||||
char *spi_dev_name = argv[2];
|
||||
rtt_dev_bak = rtt_dev;
|
||||
|
||||
/* delete the old SPI flash device */
|
||||
if(rtt_dev_bak) {
|
||||
rt_sfud_flash_delete(rtt_dev_bak);
|
||||
}
|
||||
|
||||
rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
|
||||
if (!rtt_dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
sfud_dev = (sfud_flash_t)rtt_dev->user_data;
|
||||
if (sfud_dev->chip.capacity < 1024 * 1024) {
|
||||
rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name);
|
||||
} else {
|
||||
rt_kprintf("%d MB %s is current selected device.\n", sfud_dev->chip.capacity / 1024 / 1024,
|
||||
sfud_dev->name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!sfud_dev) {
|
||||
rt_kprintf("No flash device selected. Please run 'sf probe'.\n");
|
||||
return;
|
||||
}
|
||||
if (!rt_strcmp(operator, "read")) {
|
||||
if (argc < 4) {
|
||||
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_READ_INDEX]);
|
||||
return;
|
||||
} else {
|
||||
addr = strtol(argv[2], NULL, 0);
|
||||
size = strtol(argv[3], NULL, 0);
|
||||
uint8_t *data = rt_malloc(size);
|
||||
if (data) {
|
||||
result = sfud_read(sfud_dev, addr, size, data);
|
||||
if (result == SFUD_SUCCESS) {
|
||||
rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\n",
|
||||
sfud_dev->name, addr, size);
|
||||
rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
|
||||
for (i = 0; i < size; i += HEXDUMP_WIDTH)
|
||||
{
|
||||
rt_kprintf("[%08X] ", addr + i);
|
||||
/* dump hex */
|
||||
for (j = 0; j < HEXDUMP_WIDTH; j++) {
|
||||
if (i + j < size) {
|
||||
rt_kprintf("%02X ", data[i + j]);
|
||||
} else {
|
||||
rt_kprintf(" ");
|
||||
}
|
||||
}
|
||||
/* dump char for hex */
|
||||
for (j = 0; j < HEXDUMP_WIDTH; j++) {
|
||||
if (i + j < size) {
|
||||
rt_kprintf("%c", __is_print(data[i + j]) ? data[i + j] : '.');
|
||||
}
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
rt_free(data);
|
||||
} else {
|
||||
rt_kprintf("Low memory!\n");
|
||||
}
|
||||
}
|
||||
} else if (!rt_strcmp(operator, "write")) {
|
||||
if (argc < 4) {
|
||||
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_WRITE_INDEX]);
|
||||
return;
|
||||
} else {
|
||||
addr = strtol(argv[2], NULL, 0);
|
||||
size = argc - 3;
|
||||
uint8_t *data = rt_malloc(size);
|
||||
if (data) {
|
||||
for (i = 0; i < size; i++) {
|
||||
data[i] = strtol(argv[3 + i], NULL, 0);
|
||||
}
|
||||
result = sfud_write(sfud_dev, addr, size, data);
|
||||
if (result == SFUD_SUCCESS) {
|
||||
rt_kprintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n",
|
||||
sfud_dev->name, addr, size);
|
||||
rt_kprintf("Write data: ");
|
||||
for (i = 0; i < size; i++) {
|
||||
rt_kprintf("%d ", data[i]);
|
||||
}
|
||||
rt_kprintf(".\n");
|
||||
}
|
||||
rt_free(data);
|
||||
} else {
|
||||
rt_kprintf("Low memory!\n");
|
||||
}
|
||||
}
|
||||
} else if (!rt_strcmp(operator, "erase")) {
|
||||
if (argc < 4) {
|
||||
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_ERASE_INDEX]);
|
||||
return;
|
||||
} else {
|
||||
addr = strtol(argv[2], NULL, 0);
|
||||
size = strtol(argv[3], NULL, 0);
|
||||
result = sfud_erase(sfud_dev, addr, size);
|
||||
if (result == SFUD_SUCCESS) {
|
||||
rt_kprintf("Erase the %s flash data success. Start from 0x%08X, size is %ld.\n", sfud_dev->name,
|
||||
addr, size);
|
||||
}
|
||||
}
|
||||
} else if (!rt_strcmp(operator, "status")) {
|
||||
if (argc < 3) {
|
||||
uint8_t status;
|
||||
result = sfud_read_status(sfud_dev, &status);
|
||||
if (result == SFUD_SUCCESS) {
|
||||
rt_kprintf("The %s flash status register current value is 0x%02X.\n", sfud_dev->name, status);
|
||||
}
|
||||
} else if (argc == 4) {
|
||||
bool is_volatile = strtol(argv[2], NULL, 0);
|
||||
uint8_t status = strtol(argv[3], NULL, 0);
|
||||
result = sfud_write_status(sfud_dev, is_volatile, status);
|
||||
if (result == SFUD_SUCCESS) {
|
||||
rt_kprintf("Write the %s flash status register to 0x%02X success.\n", sfud_dev->name, status);
|
||||
}
|
||||
} else {
|
||||
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_RW_STATUS_INDEX]);
|
||||
return;
|
||||
}
|
||||
} else if (!rt_strcmp(operator, "bench")) {
|
||||
if ((argc > 2 && rt_strcmp(argv[2], "yes")) || argc < 3) {
|
||||
rt_kprintf("DANGER: It will erase full chip! Please run 'sf bench yes'.\n");
|
||||
return;
|
||||
}
|
||||
/* full chip benchmark test */
|
||||
addr = 0;
|
||||
size = sfud_dev->chip.capacity;
|
||||
uint32_t start_time, time_cast;
|
||||
size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = SFUD_WRITE_MAX_PAGE_SIZE, cur_op_size;
|
||||
uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size);
|
||||
|
||||
if (write_data && read_data) {
|
||||
for (i = 0; i < write_size; i ++) {
|
||||
write_data[i] = i & 0xFF;
|
||||
}
|
||||
/* benchmark testing */
|
||||
rt_kprintf("Erasing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
|
||||
start_time = rt_tick_get();
|
||||
result = sfud_erase(sfud_dev, addr, size);
|
||||
if (result == SFUD_SUCCESS) {
|
||||
time_cast = rt_tick_get() - start_time;
|
||||
rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
|
||||
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
|
||||
} else {
|
||||
rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
|
||||
}
|
||||
/* write test */
|
||||
rt_kprintf("Writing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
|
||||
start_time = rt_tick_get();
|
||||
for (i = 0; i < size; i += write_size) {
|
||||
if (i + write_size <= size) {
|
||||
cur_op_size = write_size;
|
||||
} else {
|
||||
cur_op_size = size - i;
|
||||
}
|
||||
result = sfud_write(sfud_dev, addr + i, cur_op_size, write_data);
|
||||
if (result != SFUD_SUCCESS) {
|
||||
rt_kprintf("Writing %s failed, already wr for %lu bytes, write %d each time\n", sfud_dev->name, i, write_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == SFUD_SUCCESS) {
|
||||
time_cast = rt_tick_get() - start_time;
|
||||
rt_kprintf("Write benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
|
||||
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
|
||||
} else {
|
||||
rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
|
||||
}
|
||||
/* read test */
|
||||
rt_kprintf("Reading the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
|
||||
start_time = rt_tick_get();
|
||||
for (i = 0; i < size; i += read_size) {
|
||||
if (i + read_size <= size) {
|
||||
cur_op_size = read_size;
|
||||
} else {
|
||||
cur_op_size = size - i;
|
||||
}
|
||||
result = sfud_read(sfud_dev, addr + i, cur_op_size, read_data);
|
||||
/* data check */
|
||||
if (memcmp(write_data, read_data, cur_op_size))
|
||||
{
|
||||
rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
|
||||
result = SFUD_ERR_READ;
|
||||
}
|
||||
|
||||
if (result != SFUD_SUCCESS) {
|
||||
rt_kprintf("Read %s failed, already rd for %lu bytes, read %d each time\n", sfud_dev->name, i, read_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == SFUD_SUCCESS) {
|
||||
time_cast = rt_tick_get() - start_time;
|
||||
rt_kprintf("Read benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
|
||||
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
|
||||
} else {
|
||||
rt_kprintf("Read benchmark has an error. Error code: %d.\n", result);
|
||||
}
|
||||
} else {
|
||||
rt_kprintf("Low memory!\n");
|
||||
}
|
||||
rt_free(write_data);
|
||||
rt_free(read_data);
|
||||
} else {
|
||||
rt_kprintf("Usage:\n");
|
||||
for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
|
||||
rt_kprintf("%s\n", sf_help_info[i]);
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
return;
|
||||
}
|
||||
if (result != SFUD_SUCCESS) {
|
||||
rt_kprintf("This flash operate has an error. Error code: %d.\n", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MSH_CMD_EXPORT(sf, SPI Flash operate.);
|
||||
#endif /* defined(RT_USING_FINSH) */
|
||||
|
||||
#endif /* RT_USING_SFUD */
|
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016-09-28 armink first version.
|
||||
*/
|
||||
|
||||
#ifndef _SPI_FLASH_SFUD_H_
|
||||
#define _SPI_FLASH_SFUD_H_
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "./sfud/inc/sfud.h"
|
||||
#include "spi_flash.h"
|
||||
|
||||
/**
|
||||
* Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
|
||||
*
|
||||
* @param spi_flash_dev_name the name which will create SPI flash device
|
||||
* @param spi_dev_name using SPI device name
|
||||
*
|
||||
* @return probed SPI flash device, probe failed will return RT_NULL
|
||||
*/
|
||||
rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name);
|
||||
|
||||
/**
|
||||
* Probe SPI flash by SFUD (Serial Flash Universal Driver) driver library and though SPI device by specified configuration.
|
||||
*
|
||||
* @param spi_flash_dev_name the name which will create SPI flash device
|
||||
* @param spi_dev_name using SPI device name
|
||||
* @param spi_cfg SPI device configuration
|
||||
* @param qspi_cfg QSPI device configuration
|
||||
*
|
||||
* @return probed SPI flash device, probe failed will return RT_NULL
|
||||
*/
|
||||
rt_spi_flash_device_t rt_sfud_flash_probe_ex(const char *spi_flash_dev_name, const char *spi_dev_name,
|
||||
struct rt_spi_configuration *spi_cfg, struct rt_qspi_configuration *qspi_cfg);
|
||||
|
||||
/**
|
||||
* Delete SPI flash device
|
||||
*
|
||||
* @param spi_flash_dev SPI flash device
|
||||
*
|
||||
* @return the operation status, RT_EOK on successful
|
||||
*/
|
||||
rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev);
|
||||
|
||||
/**
|
||||
* Find sfud flash device by SPI device name
|
||||
*
|
||||
* @param spi_dev_name using SPI device name
|
||||
*
|
||||
* @return sfud flash device if success, otherwise return RT_NULL
|
||||
*/
|
||||
sfud_flash_t rt_sfud_flash_find(const char *spi_dev_name);
|
||||
|
||||
/**
|
||||
* Find sfud flash device by flash device name
|
||||
*
|
||||
* @param flash_dev_name using flash device name
|
||||
*
|
||||
* @return sfud flash device if success, otherwise return RT_NULL
|
||||
*/
|
||||
sfud_flash_t rt_sfud_flash_find_by_dev_name(const char *flash_dev_name);
|
||||
|
||||
#endif /* _SPI_FLASH_SFUD_H_ */
|
File diff suppressed because it is too large
Load Diff
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-04-17 Bernard first version.
|
||||
*/
|
||||
|
||||
#ifndef SPI_MSD_H_INCLUDED
|
||||
#define SPI_MSD_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtdevice.h>
|
||||
#include <drivers/spi.h>
|
||||
|
||||
/* SD command (SPI mode) */
|
||||
#define GO_IDLE_STATE 0 /* CMD0 R1 */
|
||||
#define SEND_OP_COND 1 /* CMD1 R1 */
|
||||
#define SWITCH_FUNC 6 /* CMD6 R1 */
|
||||
#define SEND_IF_COND 8 /* CMD8 R7 */
|
||||
#define SEND_CSD 9 /* CMD9 R1 */
|
||||
#define SEND_CID 10 /* CMD10 R1 */
|
||||
#define STOP_TRANSMISSION 12 /* CMD12 R1B */
|
||||
#define SEND_STATUS 13 /* CMD13 R2 */
|
||||
#define SET_BLOCKLEN 16 /* CMD16 R1 */
|
||||
#define READ_SINGLE_BLOCK 17 /* CMD17 R1 */
|
||||
#define READ_MULTIPLE_BLOCK 18 /* CMD18 R1 */
|
||||
#define WRITE_BLOCK 24 /* CMD24 R1 */
|
||||
#define WRITE_MULTIPLE_BLOCK 25 /* CMD25 R1 */
|
||||
#define PROGRAM_CSD 27 /* CMD27 R1 */
|
||||
#define SET_WRITE_PROT 28 /* CMD28 R1B */
|
||||
#define CLR_WRITE_PROT 29 /* CMD29 R1B */
|
||||
#define SEND_WRITE_PROT 30 /* CMD30 R1 */
|
||||
#define ERASE_WR_BLK_START_ADDR 32 /* CMD32 R1 */
|
||||
#define ERASE_WR_BLK_END_ADDR 33 /* CMD33 R1 */
|
||||
#define ERASE 38 /* CMD38 R1B */
|
||||
#define LOCK_UNLOCK 42 /* CMD42 R1 */
|
||||
#define APP_CMD 55 /* CMD55 R1 */
|
||||
#define GEN_CMD 56 /* CMD56 R1 */
|
||||
#define READ_OCR 58 /* CMD58 R3 */
|
||||
#define CRC_ON_OFF 59 /* CMD59 R1 */
|
||||
|
||||
/* Application-Specific Command */
|
||||
#define SD_STATUS 13 /* ACMD13 R2 */
|
||||
#define SEND_NUM_WR_BLOCKS 22 /* ACMD22 R1 */
|
||||
#define SET_WR_BLK_ERASE_COUNT 23 /* ACMD23 R1 */
|
||||
#define SD_SEND_OP_COND 41 /* ACMD41 R1 */
|
||||
#define SET_CLR_CARD_DETECT 42 /* ACMD42 R1 */
|
||||
#define SEND_SCR 51 /* ACMD51 R1 */
|
||||
|
||||
/* Start Data tokens */
|
||||
/* Tokens (necessary because at nop/idle (and CS active) only 0xff is on the data/command line) */
|
||||
#define MSD_TOKEN_READ_START 0xFE /* Data token start byte, Start Single Block Read */
|
||||
#define MSD_TOKEN_WRITE_SINGLE_START 0xFE /* Data token start byte, Start Single Block Write */
|
||||
|
||||
#define MSD_TOKEN_WRITE_MULTIPLE_START 0xFC /* Data token start byte, Start Multiple Block Write */
|
||||
#define MSD_TOKEN_WRITE_MULTIPLE_STOP 0xFD /* Data toke stop byte, Stop Multiple Block Write */
|
||||
|
||||
/* MSD reponses and error flags */
|
||||
#define MSD_RESPONSE_NO_ERROR 0x00
|
||||
#define MSD_IN_IDLE_STATE 0x01
|
||||
#define MSD_ERASE_RESET 0x02
|
||||
#define MSD_ILLEGAL_COMMAND 0x04
|
||||
#define MSD_COM_CRC_ERROR 0x08
|
||||
#define MSD_ERASE_SEQUENCE_ERROR 0x10
|
||||
#define MSD_ADDRESS_ERROR 0x20
|
||||
#define MSD_PARAMETER_ERROR 0x40
|
||||
#define MSD_RESPONSE_FAILURE 0xFF
|
||||
|
||||
/* Data response error */
|
||||
#define MSD_DATA_OK 0x05
|
||||
#define MSD_DATA_CRC_ERROR 0x0B
|
||||
#define MSD_DATA_WRITE_ERROR 0x0D
|
||||
#define MSD_DATA_OTHER_ERROR 0xFF
|
||||
#define MSD_DATA_RESPONSE_MASK 0x1F
|
||||
#define MSD_GET_DATA_RESPONSE(res) (res & MSD_DATA_RESPONSE_MASK)
|
||||
|
||||
#define MSD_CMD_LEN 6 /**< command, arg and crc. */
|
||||
#define MSD_RESPONSE_MAX_LEN 5 /**< response max len */
|
||||
#define MSD_CSD_LEN 16 /**< SD crad CSD register len */
|
||||
#define SECTOR_SIZE 512 /**< sector size, default 512byte */
|
||||
|
||||
/* card try timeout, unit: ms */
|
||||
#define CARD_TRY_TIMES 3000
|
||||
#define CARD_TRY_TIMES_ACMD41 800
|
||||
#define CARD_WAIT_TOKEN_TIMES 800
|
||||
|
||||
#define MSD_USE_PRE_ERASED /**< id define MSD_USE_PRE_ERASED, before CMD25, send ACMD23 */
|
||||
|
||||
/**
|
||||
* SD/MMC card type
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MSD_CARD_TYPE_UNKNOWN = 0, /**< unknown */
|
||||
MSD_CARD_TYPE_MMC, /**< MultiMedia Card */
|
||||
MSD_CARD_TYPE_SD_V1_X, /**< Ver 1.X Standard Capacity SD Memory Card */
|
||||
MSD_CARD_TYPE_SD_V2_X, /**< Ver 2.00 or later Standard Capacity SD Memory Card */
|
||||
MSD_CARD_TYPE_SD_SDHC, /**< High Capacity SD Memory Card */
|
||||
MSD_CARD_TYPE_SD_SDXC, /**< later Extended Capacity SD Memory Card */
|
||||
}msd_card_type;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
response_type_unknown = 0,
|
||||
response_r1,
|
||||
response_r1b,
|
||||
response_r2,
|
||||
response_r3,
|
||||
response_r4,
|
||||
response_r5,
|
||||
response_r7,
|
||||
}response_type;
|
||||
|
||||
struct msd_device
|
||||
{
|
||||
struct rt_device parent; /**< RT-Thread device struct */
|
||||
struct rt_device_blk_geometry geometry; /**< sector size, sector count */
|
||||
struct rt_spi_device * spi_device; /**< SPI interface */
|
||||
msd_card_type card_type; /**< card type: MMC SD1.x SD2.0 SDHC SDXC */
|
||||
uint32_t max_clock; /**< MAX SPI clock */
|
||||
};
|
||||
|
||||
extern rt_err_t msd_init(const char * sd_device_name, const char * spi_device_name);
|
||||
|
||||
#endif // SPI_MSD_H_INCLUDED
|
@@ -1,852 +0,0 @@
|
||||
/*
|
||||
* COPYRIGHT (C) 2011-2023, Real-Thread Information Technology Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-07-31 aozima the first version
|
||||
* 2014-09-18 aozima update command & response.
|
||||
* 2017-07-28 armink fix auto reconnect feature
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <drivers/spi.h>
|
||||
|
||||
#include <netif/ethernetif.h>
|
||||
#include <netif/etharp.h>
|
||||
#include <lwip/icmp.h>
|
||||
#include "lwipopts.h"
|
||||
|
||||
#define WIFI_DEBUG_ON
|
||||
// #define ETH_RX_DUMP
|
||||
// #define ETH_TX_DUMP
|
||||
|
||||
#ifdef WIFI_DEBUG_ON
|
||||
#define WIFI_DEBUG rt_kprintf("[RW009] ");rt_kprintf
|
||||
//#define SPI_DEBUG rt_kprintf("[SPI] ");rt_kprintf
|
||||
#define SPI_DEBUG(...)
|
||||
#else
|
||||
#define WIFI_DEBUG(...)
|
||||
#define SPI_DEBUG(...)
|
||||
#endif /* #ifdef WIFI_DEBUG_ON */
|
||||
|
||||
/********************************* RW009 **************************************/
|
||||
#include "spi_wifi_rw009.h"
|
||||
|
||||
/* tools */
|
||||
#define node_entry(node, type, member) \
|
||||
((type *)((char *)(node) - (unsigned long)(&((type *)0)->member)))
|
||||
#define member_offset(type, member) \
|
||||
((unsigned long)(&((type *)0)->member))
|
||||
|
||||
#define MAX_SPI_PACKET_SIZE (member_offset(struct spi_data_packet, buffer) + SPI_MAX_DATA_LEN)
|
||||
#define MAX_SPI_BUFFER_SIZE (sizeof(struct spi_response) + MAX_SPI_PACKET_SIZE)
|
||||
#define MAX_ADDR_LEN 6
|
||||
|
||||
struct rw009_wifi
|
||||
{
|
||||
/* inherit from ethernet device */
|
||||
struct eth_device parent;
|
||||
|
||||
struct rt_spi_device *rt_spi_device;
|
||||
|
||||
/* interface address info. */
|
||||
rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
|
||||
rt_uint8_t active;
|
||||
|
||||
struct rt_mempool spi_tx_mp;
|
||||
struct rt_mempool spi_rx_mp;
|
||||
|
||||
struct rt_mailbox spi_tx_mb;
|
||||
struct rt_mailbox eth_rx_mb;
|
||||
|
||||
int spi_tx_mb_pool[SPI_TX_POOL_SIZE + 1];
|
||||
int eth_rx_mb_pool[SPI_RX_POOL_SIZE + 1];
|
||||
|
||||
int rw009_cmd_mb_pool[3];
|
||||
struct rt_mailbox rw009_cmd_mb;
|
||||
uint32_t last_cmd;
|
||||
|
||||
rt_align(4)
|
||||
rt_uint8_t spi_tx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE];
|
||||
rt_align(4)
|
||||
rt_uint8_t spi_rx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_RX_POOL_SIZE];
|
||||
|
||||
rt_align(4)
|
||||
uint8_t spi_hw_rx_buffer[MAX_SPI_BUFFER_SIZE];
|
||||
|
||||
/* status for RW009 */
|
||||
rw009_ap_info ap_info; /* AP info for conn. */
|
||||
rw009_ap_info *ap_scan; /* AP list for SCAN. */
|
||||
uint32_t ap_scan_count;
|
||||
};
|
||||
static struct rw009_wifi rw009_wifi_device;
|
||||
static struct rt_event spi_wifi_data_event;
|
||||
|
||||
static void resp_handler(struct rw009_wifi *wifi_device, struct rw009_resp *resp)
|
||||
{
|
||||
struct rw009_resp *resp_return = RT_NULL;
|
||||
|
||||
switch (resp->cmd)
|
||||
{
|
||||
case RW009_CMD_INIT:
|
||||
WIFI_DEBUG("resp_handler RW009_CMD_INIT\n");
|
||||
resp_return = (struct rw009_resp *)rt_malloc(member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_init)); //TODO:
|
||||
if(resp_return == RT_NULL) break;
|
||||
rt_memcpy(resp_return, resp, member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_init));
|
||||
|
||||
WIFI_DEBUG("sn:%-*.*s\n", sizeof(resp->resp.init.sn), sizeof(resp->resp.init.sn), resp->resp.init.sn);
|
||||
WIFI_DEBUG("version:%-*.*s\n", sizeof(resp->resp.init.version), sizeof(resp->resp.init.version), resp->resp.init.version);
|
||||
|
||||
rt_memcpy(wifi_device->dev_addr, resp->resp.init.mac, 6);
|
||||
break;
|
||||
|
||||
case RW009_CMD_SCAN:
|
||||
if( resp->len == sizeof(rw009_ap_info) )
|
||||
{
|
||||
rw009_ap_info *ap_scan = rt_realloc(wifi_device->ap_scan, sizeof(rw009_ap_info) * (wifi_device->ap_scan_count + 1) );
|
||||
if(ap_scan != RT_NULL)
|
||||
{
|
||||
rt_memcpy( &ap_scan[wifi_device->ap_scan_count], &resp->resp.ap_info, sizeof(rw009_ap_info) );
|
||||
|
||||
//dump
|
||||
if(1)
|
||||
{
|
||||
#ifdef WIFI_DEBUG_ON
|
||||
rw009_ap_info *ap_info = &resp->resp.ap_info;
|
||||
WIFI_DEBUG("SCAN SSID:%-32.32s\n", ap_info->ssid);
|
||||
WIFI_DEBUG("SCAN BSSID:%02X-%02X-%02X-%02X-%02X-%02X\n",
|
||||
ap_info->bssid[0],
|
||||
ap_info->bssid[1],
|
||||
ap_info->bssid[2],
|
||||
ap_info->bssid[3],
|
||||
ap_info->bssid[4],
|
||||
ap_info->bssid[5]);
|
||||
WIFI_DEBUG("SCAN rssi:%ddBm\n", ap_info->rssi);
|
||||
WIFI_DEBUG("SCAN rate:%dMbps\n", ap_info->max_data_rate/1000);
|
||||
WIFI_DEBUG("SCAN channel:%d\n", ap_info->channel);
|
||||
WIFI_DEBUG("SCAN security:%08X\n\n", ap_info->security);
|
||||
#endif /* WIFI_DEBUG_ON */
|
||||
}
|
||||
|
||||
wifi_device->ap_scan_count++;
|
||||
wifi_device->ap_scan = ap_scan;
|
||||
}
|
||||
|
||||
return; /* wait for next ap */
|
||||
}
|
||||
break;
|
||||
case RW009_CMD_JOIN:
|
||||
case RW009_CMD_EASY_JOIN:
|
||||
WIFI_DEBUG("resp_handler RW009_CMD_EASY_JOIN\n");
|
||||
resp_return = (struct rw009_resp *)rt_malloc(member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_join)); //TODO:
|
||||
if(resp_return == RT_NULL) break;
|
||||
rt_memcpy(resp_return, resp, member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_join));
|
||||
|
||||
if( resp->result == 0 )
|
||||
{
|
||||
rt_memcpy(&wifi_device->ap_info, &resp_return->resp.ap_info, sizeof(rw009_resp_join));
|
||||
wifi_device->active = 1;
|
||||
eth_device_linkchange(&wifi_device->parent, RT_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
wifi_device->active = 1;
|
||||
eth_device_linkchange(&wifi_device->parent, RT_FALSE);
|
||||
WIFI_DEBUG("RW009_CMD_EASY_JOIN result: %d\n", resp->result );
|
||||
}
|
||||
|
||||
//dupm
|
||||
if(1)
|
||||
{
|
||||
#ifdef WIFI_DEBUG_ON
|
||||
rw009_ap_info *ap_info = &resp->resp.ap_info;
|
||||
WIFI_DEBUG("JOIN SSID:%-32.32s\n", ap_info->ssid);
|
||||
WIFI_DEBUG("JOIN BSSID:%02X-%02X-%02X-%02X-%02X-%02X\n",
|
||||
ap_info->bssid[0],
|
||||
ap_info->bssid[1],
|
||||
ap_info->bssid[2],
|
||||
ap_info->bssid[3],
|
||||
ap_info->bssid[4],
|
||||
ap_info->bssid[5]);
|
||||
WIFI_DEBUG("JOIN rssi:%ddBm\n", ap_info->rssi);
|
||||
WIFI_DEBUG("JOIN rate:%dMbps\n", ap_info->max_data_rate/1000);
|
||||
WIFI_DEBUG("JOIN channel:%d\n", ap_info->channel);
|
||||
WIFI_DEBUG("JOIN security:%08X\n\n", ap_info->security);
|
||||
#endif /* WIFI_DEBUG_ON */
|
||||
}
|
||||
break;
|
||||
|
||||
case RW009_CMD_RSSI:
|
||||
// TODO: client RSSI.
|
||||
{
|
||||
rw009_ap_info *ap_info = &resp->resp.ap_info;
|
||||
wifi_device->ap_info.rssi = ap_info->rssi;
|
||||
WIFI_DEBUG("current RSSI: %d\n", wifi_device->ap_info.rssi);
|
||||
}
|
||||
break;
|
||||
|
||||
case RW009_CMD_SOFTAP:
|
||||
{
|
||||
if( resp->result == 0 )
|
||||
{
|
||||
;
|
||||
wifi_device->active = 1;
|
||||
eth_device_linkchange(&wifi_device->parent, RT_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
WIFI_DEBUG("RW009_CMD_EASY_JOIN result: %d\n", resp->result );
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WIFI_DEBUG("resp_handler %d\n", resp->cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(resp->cmd == wifi_device->last_cmd)
|
||||
{
|
||||
rt_mb_send(&wifi_device->rw009_cmd_mb, (rt_uint32_t)resp_return);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_free(resp_return);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t rw009_cmd(struct rw009_wifi *wifi_device, uint32_t cmd, void *args)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_int32_t timeout = RW009_CMD_TIMEOUT;
|
||||
|
||||
struct spi_data_packet *data_packet;
|
||||
struct rw009_cmd *wifi_cmd = RT_NULL;
|
||||
struct rw009_resp *resp = RT_NULL;
|
||||
|
||||
wifi_device->last_cmd = cmd;
|
||||
|
||||
data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
|
||||
wifi_cmd = (struct rw009_cmd *)data_packet->buffer;
|
||||
|
||||
wifi_cmd->cmd = cmd;
|
||||
wifi_cmd->len = 0;
|
||||
|
||||
if( cmd == RW009_CMD_INIT )
|
||||
{
|
||||
wifi_cmd->len = sizeof(rw009_cmd_init);
|
||||
}
|
||||
else if( cmd == RW009_CMD_SCAN )
|
||||
{
|
||||
wifi_cmd->len = 0;
|
||||
timeout += RT_TICK_PER_SECOND*10;
|
||||
|
||||
if(wifi_device->ap_scan)
|
||||
{
|
||||
rt_free(wifi_device->ap_scan);
|
||||
wifi_device->ap_scan = RT_NULL;
|
||||
wifi_device->ap_scan_count = 0;
|
||||
}
|
||||
}
|
||||
else if( cmd == RW009_CMD_JOIN )
|
||||
{
|
||||
wifi_cmd->len = sizeof(rw009_cmd_join);
|
||||
}
|
||||
else if( cmd == RW009_CMD_EASY_JOIN )
|
||||
{
|
||||
wifi_cmd->len = sizeof(rw009_cmd_easy_join);
|
||||
timeout += RT_TICK_PER_SECOND*5;
|
||||
}
|
||||
else if( cmd == RW009_CMD_RSSI )
|
||||
{
|
||||
wifi_cmd->len = sizeof(rw009_cmd_rssi);
|
||||
}
|
||||
else if( cmd == RW009_CMD_SOFTAP )
|
||||
{
|
||||
wifi_cmd->len = sizeof(rw009_cmd_softap);
|
||||
}
|
||||
else
|
||||
{
|
||||
WIFI_DEBUG("unkown RW009 CMD %d\n", cmd);
|
||||
result = -RT_ENOSYS;
|
||||
rt_mp_free(data_packet);
|
||||
data_packet = RT_NULL;
|
||||
}
|
||||
|
||||
if(data_packet == RT_NULL)
|
||||
{
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if(wifi_cmd->len)
|
||||
rt_memcpy(&wifi_cmd->params, args, wifi_cmd->len);
|
||||
|
||||
data_packet->data_type = data_type_cmd;
|
||||
data_packet->data_len = member_offset(struct rw009_cmd, params) + wifi_cmd->len;
|
||||
|
||||
rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
|
||||
rt_event_send(&spi_wifi_data_event, 1);
|
||||
|
||||
result = rt_mb_recv(&wifi_device->rw009_cmd_mb,
|
||||
(rt_uint32_t *)&resp,
|
||||
timeout);
|
||||
|
||||
if ( result != RT_EOK )
|
||||
{
|
||||
WIFI_DEBUG("CMD %d error, resultL %d\n", cmd, result );
|
||||
}
|
||||
|
||||
if(resp != RT_NULL)
|
||||
result = resp->result;
|
||||
|
||||
_exit:
|
||||
wifi_device->last_cmd = 0;
|
||||
if(resp) rt_free(resp);
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t spi_wifi_transfer(struct rw009_wifi *dev)
|
||||
{
|
||||
struct pbuf *p = RT_NULL;
|
||||
struct spi_cmd_request cmd;
|
||||
struct spi_response resp;
|
||||
|
||||
rt_err_t result;
|
||||
const struct spi_data_packet *data_packet = RT_NULL;
|
||||
|
||||
struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
|
||||
struct rt_spi_device *rt_spi_device = wifi_device->rt_spi_device;
|
||||
|
||||
spi_wifi_int_cmd(0);
|
||||
while (spi_wifi_is_busy());
|
||||
SPI_DEBUG("sequence start!\n");
|
||||
|
||||
rt_memset(&cmd, 0, sizeof(struct spi_cmd_request));
|
||||
cmd.magic1 = CMD_MAGIC1;
|
||||
cmd.magic2 = CMD_MAGIC2;
|
||||
|
||||
cmd.flag |= CMD_FLAG_MRDY;
|
||||
|
||||
result = rt_mb_recv(&wifi_device->spi_tx_mb,
|
||||
(rt_uint32_t *)&data_packet,
|
||||
0);
|
||||
if ((result == RT_EOK) && (data_packet != RT_NULL) && (data_packet->data_len > 0))
|
||||
{
|
||||
cmd.M2S_len = data_packet->data_len + member_offset(struct spi_data_packet, buffer);
|
||||
//SPI_DEBUG("cmd.M2S_len = %d\n", cmd.M2S_len);
|
||||
}
|
||||
|
||||
rt_spi_send(rt_spi_device, &cmd, sizeof(cmd));
|
||||
while (spi_wifi_is_busy());
|
||||
|
||||
{
|
||||
struct rt_spi_message message;
|
||||
uint32_t max_data_len = 0;
|
||||
|
||||
/* setup message */
|
||||
message.send_buf = RT_NULL;
|
||||
message.recv_buf = &resp;
|
||||
message.length = sizeof(resp);
|
||||
message.cs_take = 1;
|
||||
message.cs_release = 0;
|
||||
|
||||
rt_spi_take_bus(rt_spi_device);
|
||||
|
||||
/* transfer message */
|
||||
rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
|
||||
|
||||
if ((resp.magic1 != RESP_MAGIC1) || (resp.magic2 != RESP_MAGIC2))
|
||||
{
|
||||
SPI_DEBUG("bad resp magic, abort!\n");
|
||||
goto _bad_resp_magic;
|
||||
}
|
||||
|
||||
if (resp.flag & RESP_FLAG_SRDY)
|
||||
{
|
||||
SPI_DEBUG("RESP_FLAG_SRDY\n");
|
||||
max_data_len = cmd.M2S_len;
|
||||
}
|
||||
|
||||
if (resp.S2M_len)
|
||||
{
|
||||
SPI_DEBUG("resp.S2M_len: %d\n", resp.S2M_len);
|
||||
if (resp.S2M_len > MAX_SPI_PACKET_SIZE)
|
||||
{
|
||||
SPI_DEBUG("resp.S2M_len %d > %d(MAX_SPI_PACKET_SIZE), drop!\n", resp.S2M_len, MAX_SPI_PACKET_SIZE);
|
||||
resp.S2M_len = 0;//drop
|
||||
}
|
||||
|
||||
if (resp.S2M_len > max_data_len)
|
||||
max_data_len = resp.S2M_len;
|
||||
}
|
||||
|
||||
if (max_data_len == 0)
|
||||
{
|
||||
SPI_DEBUG("no rx or tx data!\n");
|
||||
}
|
||||
|
||||
//SPI_DEBUG("max_data_len = %d\n", max_data_len);
|
||||
|
||||
_bad_resp_magic:
|
||||
/* setup message */
|
||||
message.send_buf = data_packet;//&tx_buffer;
|
||||
message.recv_buf = wifi_device->spi_hw_rx_buffer;//&rx_buffer;
|
||||
message.length = max_data_len;
|
||||
message.cs_take = 0;
|
||||
message.cs_release = 1;
|
||||
|
||||
/* transfer message */
|
||||
rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
|
||||
|
||||
rt_spi_release_bus(rt_spi_device);
|
||||
|
||||
if (cmd.M2S_len && (resp.flag & RESP_FLAG_SRDY))
|
||||
{
|
||||
rt_mp_free((void *)data_packet);
|
||||
}
|
||||
|
||||
if ((resp.S2M_len) && (resp.S2M_len <= MAX_SPI_PACKET_SIZE))
|
||||
{
|
||||
data_packet = (struct spi_data_packet *)wifi_device->spi_hw_rx_buffer;
|
||||
if (data_packet->data_type == data_type_eth_data)
|
||||
{
|
||||
|
||||
if (wifi_device->active)
|
||||
{
|
||||
p = pbuf_alloc(PBUF_LINK, data_packet->data_len, PBUF_RAM);
|
||||
pbuf_take(p, (rt_uint8_t *)data_packet->buffer, data_packet->data_len);
|
||||
|
||||
rt_mb_send(&wifi_device->eth_rx_mb, (rt_uint32_t)p);
|
||||
eth_device_ready((struct eth_device *)dev);
|
||||
}
|
||||
else
|
||||
{
|
||||
SPI_DEBUG("!active, RX drop.\n");
|
||||
}
|
||||
}
|
||||
else if (data_packet->data_type == data_type_resp)
|
||||
{
|
||||
SPI_DEBUG("data_type_resp\n");
|
||||
resp_handler(dev, (struct rw009_resp *)data_packet->buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
SPI_DEBUG("data_type: %d, %dbyte\n",
|
||||
data_packet->data_type,
|
||||
data_packet->data_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
spi_wifi_int_cmd(1);
|
||||
|
||||
SPI_DEBUG("sequence finish!\n\n");
|
||||
|
||||
if ((cmd.M2S_len == 0) && (resp.S2M_len == 0))
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
|
||||
static void packet_dump(const char *msg, const struct pbuf *p)
|
||||
{
|
||||
const struct pbuf* q;
|
||||
rt_uint32_t i,j;
|
||||
rt_uint8_t *ptr = p->payload;
|
||||
|
||||
rt_kprintf("%s %d byte\n", msg, p->tot_len);
|
||||
|
||||
i=0;
|
||||
for(q=p; q != RT_NULL; q= q->next)
|
||||
{
|
||||
ptr = q->payload;
|
||||
|
||||
for(j=0; j<q->len; j++)
|
||||
{
|
||||
if( (i%8) == 0 )
|
||||
{
|
||||
rt_kprintf(" ");
|
||||
}
|
||||
if( (i%16) == 0 )
|
||||
{
|
||||
rt_kprintf("\r\n");
|
||||
}
|
||||
rt_kprintf("%02x ",*ptr);
|
||||
|
||||
i++;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
rt_kprintf("\n\n");
|
||||
}
|
||||
#endif /* dump */
|
||||
|
||||
/********************************* RT-Thread Ethernet interface begin **************************************/
|
||||
static rt_err_t rw009_wifi_init(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rw009_wifi_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rw009_wifi_close(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_ssize_t rw009_wifi_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_set_errno(-RT_ENOSYS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_ssize_t rw009_wifi_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_set_errno(-RT_ENOSYS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t rw009_wifi_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
if (cmd == NIOCTL_GADDR)
|
||||
{
|
||||
rt_memcpy(args, wifi_device->dev_addr, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = rw009_cmd(wifi_device, cmd, args);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* transmit packet. */
|
||||
rt_err_t rw009_wifi_tx(rt_device_t dev, struct pbuf *p)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct spi_data_packet *data_packet;
|
||||
struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
|
||||
|
||||
if (!wifi_device->active)
|
||||
{
|
||||
WIFI_DEBUG("!active, TX drop!\n");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* get free tx buffer */
|
||||
data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
|
||||
if (data_packet != RT_NULL)
|
||||
{
|
||||
data_packet->data_type = data_type_eth_data;
|
||||
data_packet->data_len = p->tot_len;
|
||||
|
||||
pbuf_copy_partial(p, data_packet->buffer, data_packet->data_len, 0);
|
||||
|
||||
rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
|
||||
rt_event_send(&spi_wifi_data_event, 1);
|
||||
}
|
||||
else
|
||||
return -RT_ERROR;
|
||||
|
||||
#ifdef ETH_TX_DUMP
|
||||
packet_dump("TX dump", p);
|
||||
#endif /* ETH_TX_DUMP */
|
||||
|
||||
/* Return SUCCESS */
|
||||
return result;
|
||||
}
|
||||
|
||||
/* reception packet. */
|
||||
struct pbuf *rw009_wifi_rx(rt_device_t dev)
|
||||
{
|
||||
struct pbuf *p = RT_NULL;
|
||||
struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
|
||||
|
||||
if (rt_mb_recv(&wifi_device->eth_rx_mb, (rt_uint32_t *)&p, 0) != RT_EOK)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
#ifdef ETH_RX_DUMP
|
||||
if(p)
|
||||
packet_dump("RX dump", p);
|
||||
#endif /* ETH_RX_DUMP */
|
||||
|
||||
return p;
|
||||
}
|
||||
/********************************* RT-Thread Ethernet interface end **************************************/
|
||||
|
||||
static void spi_wifi_data_thread_entry(void *parameter)
|
||||
{
|
||||
rt_uint32_t e;
|
||||
rt_err_t result;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* receive first event */
|
||||
if (rt_event_recv(&spi_wifi_data_event,
|
||||
1,
|
||||
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER,
|
||||
&e) != RT_EOK)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = spi_wifi_transfer(&rw009_wifi_device);
|
||||
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
rt_event_send(&spi_wifi_data_event, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops rw009_ops =
|
||||
{
|
||||
rw009_wifi_init,
|
||||
rw009_wifi_open,
|
||||
rw009_wifi_close,
|
||||
rw009_wifi_read,
|
||||
rw009_wifi_write,
|
||||
rw009_wifi_control
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_hw_wifi_init(const char *spi_device_name, wifi_mode_t mode)
|
||||
{
|
||||
/* align and struct size check. */
|
||||
RT_ASSERT( (SPI_MAX_DATA_LEN & 0x03) == 0);
|
||||
RT_ASSERT( sizeof(struct rw009_resp) <= SPI_MAX_DATA_LEN);
|
||||
|
||||
rt_memset(&rw009_wifi_device, 0, sizeof(struct rw009_wifi));
|
||||
|
||||
rw009_wifi_device.rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
|
||||
|
||||
if (rw009_wifi_device.rt_spi_device == RT_NULL)
|
||||
{
|
||||
SPI_DEBUG("spi device %s not found!\r\n", spi_device_name);
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
/* config spi */
|
||||
{
|
||||
struct rt_spi_configuration cfg;
|
||||
cfg.data_width = 8;
|
||||
cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0. */
|
||||
cfg.max_hz = 15 * 1000000; /* 10M */
|
||||
rt_spi_configure(rw009_wifi_device.rt_spi_device, &cfg);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
rw009_wifi_device.parent.parent.ops = &rw009_ops;
|
||||
#else
|
||||
rw009_wifi_device.parent.parent.init = rw009_wifi_init;
|
||||
rw009_wifi_device.parent.parent.open = rw009_wifi_open;
|
||||
rw009_wifi_device.parent.parent.close = rw009_wifi_close;
|
||||
rw009_wifi_device.parent.parent.read = rw009_wifi_read;
|
||||
rw009_wifi_device.parent.parent.write = rw009_wifi_write;
|
||||
rw009_wifi_device.parent.parent.control = rw009_wifi_control;
|
||||
#endif
|
||||
rw009_wifi_device.parent.parent.user_data = RT_NULL;
|
||||
|
||||
rw009_wifi_device.parent.eth_rx = rw009_wifi_rx;
|
||||
rw009_wifi_device.parent.eth_tx = rw009_wifi_tx;
|
||||
|
||||
rt_mp_init(&rw009_wifi_device.spi_tx_mp,
|
||||
"spi_tx",
|
||||
&rw009_wifi_device.spi_tx_mempool[0],
|
||||
sizeof(rw009_wifi_device.spi_tx_mempool),
|
||||
sizeof(struct spi_data_packet));
|
||||
|
||||
rt_mp_init(&rw009_wifi_device.spi_rx_mp,
|
||||
"spi_rx",
|
||||
&rw009_wifi_device.spi_rx_mempool[0],
|
||||
sizeof(rw009_wifi_device.spi_rx_mempool),
|
||||
sizeof(struct spi_data_packet));
|
||||
|
||||
rt_mb_init(&rw009_wifi_device.spi_tx_mb,
|
||||
"spi_tx",
|
||||
&rw009_wifi_device.spi_tx_mb_pool[0],
|
||||
SPI_TX_POOL_SIZE,
|
||||
RT_IPC_FLAG_PRIO);
|
||||
|
||||
rt_mb_init(&rw009_wifi_device.eth_rx_mb,
|
||||
"eth_rx",
|
||||
&rw009_wifi_device.eth_rx_mb_pool[0],
|
||||
SPI_TX_POOL_SIZE,
|
||||
RT_IPC_FLAG_PRIO);
|
||||
|
||||
rt_mb_init(&rw009_wifi_device.rw009_cmd_mb,
|
||||
"wifi_cmd",
|
||||
&rw009_wifi_device.rw009_cmd_mb_pool[0],
|
||||
sizeof(rw009_wifi_device.rw009_cmd_mb_pool) / 4,
|
||||
RT_IPC_FLAG_PRIO);
|
||||
rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO);
|
||||
|
||||
spi_wifi_hw_init();
|
||||
|
||||
{
|
||||
rt_thread_t tid;
|
||||
|
||||
|
||||
tid = rt_thread_create("wifi",
|
||||
spi_wifi_data_thread_entry,
|
||||
RT_NULL,
|
||||
2048,
|
||||
RT_THREAD_PRIORITY_MAX - 2,
|
||||
20);
|
||||
|
||||
if (tid != RT_NULL)
|
||||
rt_thread_startup(tid);
|
||||
}
|
||||
|
||||
/* init: get mac address */
|
||||
{
|
||||
rw009_cmd_init init;
|
||||
init.mode = mode;
|
||||
WIFI_DEBUG("wifi_control RW009_CMD_INIT\n");
|
||||
rw009_wifi_control((rt_device_t)&rw009_wifi_device,
|
||||
RW009_CMD_INIT,
|
||||
(void *)&init); // 0: firmware, 1: STA, 2:AP
|
||||
|
||||
}
|
||||
|
||||
/* register eth device */
|
||||
eth_device_init(&(rw009_wifi_device.parent), "w0");
|
||||
eth_device_linkchange(&rw009_wifi_device.parent, RT_FALSE);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void spi_wifi_isr(int vector)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
SPI_DEBUG("spi_wifi_isr\n");
|
||||
rt_event_send(&spi_wifi_data_event, 1);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
/********************************* RW009 tools **************************************/
|
||||
rt_err_t rw009_join(const char * SSID, const char * passwd)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_device_t wifi_device;
|
||||
rw009_cmd_easy_join easy_join;
|
||||
|
||||
wifi_device = rt_device_find("w0");
|
||||
if(wifi_device == RT_NULL)
|
||||
return -RT_ENOSYS;
|
||||
|
||||
strncpy( easy_join.ssid, SSID, sizeof(easy_join.ssid) );
|
||||
strncpy( easy_join.passwd, passwd, sizeof(easy_join.passwd) );
|
||||
|
||||
result = rt_device_control(wifi_device,
|
||||
RW009_CMD_EASY_JOIN,
|
||||
(void *)&easy_join);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rw009_softap(const char * SSID, const char * passwd,uint32_t security,uint32_t channel)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_device_t wifi_device;
|
||||
rw009_cmd_softap softap;
|
||||
|
||||
wifi_device = rt_device_find("w0");
|
||||
if(wifi_device == RT_NULL)
|
||||
return -RT_ENOSYS;
|
||||
|
||||
strncpy( softap.ssid, SSID, sizeof(softap.ssid) );
|
||||
strncpy( softap.passwd, passwd, sizeof(softap.passwd) );
|
||||
|
||||
softap.security = security;
|
||||
softap.channel = channel;
|
||||
result = rt_device_control(wifi_device,
|
||||
RW009_CMD_SOFTAP,
|
||||
(void *)&softap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t rw009_rssi(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct rw009_wifi * wifi_device;
|
||||
|
||||
wifi_device = (struct rw009_wifi *)rt_device_find("w0");
|
||||
|
||||
if(wifi_device == RT_NULL)
|
||||
return 0;
|
||||
|
||||
if(wifi_device->active == 0)
|
||||
return 0;
|
||||
|
||||
// SCAN
|
||||
result = rt_device_control((rt_device_t)wifi_device,
|
||||
RW009_CMD_RSSI,
|
||||
RT_NULL);
|
||||
|
||||
if(result == RT_EOK)
|
||||
{
|
||||
return wifi_device->ap_info.rssi;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
|
||||
static rt_err_t rw009_scan(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct rw009_wifi * wifi_device;
|
||||
|
||||
wifi_device = (struct rw009_wifi *)rt_device_find("w0");
|
||||
|
||||
rt_kprintf("\nCMD RW009_CMD_SCAN \n");
|
||||
result = rt_device_control((rt_device_t)wifi_device,
|
||||
RW009_CMD_SCAN,
|
||||
RT_NULL);
|
||||
|
||||
rt_kprintf("CMD RW009_CMD_SCAN result:%d\n", result);
|
||||
|
||||
if(result == RT_EOK)
|
||||
{
|
||||
uint32_t i;
|
||||
rw009_ap_info *ap_info;
|
||||
|
||||
for(i=0; i<wifi_device->ap_scan_count; i++)
|
||||
{
|
||||
ap_info = &wifi_device->ap_scan[i];
|
||||
rt_kprintf("AP #%02d SSID: %-32.32s\n", i, ap_info->ssid );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(rw009_scan, SACN and list AP.);
|
||||
FINSH_FUNCTION_EXPORT(rw009_join, RW009 join to AP.);
|
||||
FINSH_FUNCTION_EXPORT(rw009_rssi, get RW009 current AP rssi.);
|
||||
|
||||
#endif // RT_USING_FINSH
|
@@ -1,212 +0,0 @@
|
||||
/*
|
||||
* COPYRIGHT (C) 2011-2023, Real-Thread Information Technology Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-07-31 aozima the first version
|
||||
* 2014-09-18 aozima update command & response.
|
||||
*/
|
||||
|
||||
#ifndef SPI_WIFI_H_INCLUDED
|
||||
#define SPI_WIFI_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// little-endian
|
||||
struct spi_cmd_request
|
||||
{
|
||||
uint32_t flag;
|
||||
uint32_t M2S_len; // master to slave data len.
|
||||
uint32_t magic1;
|
||||
uint32_t magic2;
|
||||
};
|
||||
|
||||
#define CMD_MAGIC1 (0x67452301)
|
||||
#define CMD_MAGIC2 (0xEFCDAB89)
|
||||
|
||||
#define CMD_FLAG_MRDY (0x01)
|
||||
|
||||
// little-endian
|
||||
struct spi_response
|
||||
{
|
||||
uint32_t flag;
|
||||
uint32_t S2M_len; // slave to master data len.
|
||||
uint32_t magic1;
|
||||
uint32_t magic2;
|
||||
};
|
||||
|
||||
#define RESP_FLAG_SRDY (0x01)
|
||||
#define RESP_MAGIC1 (0x98BADCFE)
|
||||
#define RESP_MAGIC2 (0x10325476)
|
||||
|
||||
/* spi slave configure. */
|
||||
#define SPI_MAX_DATA_LEN 1520
|
||||
#define SPI_TX_POOL_SIZE 2
|
||||
#define SPI_RX_POOL_SIZE 2
|
||||
|
||||
typedef enum
|
||||
{
|
||||
data_type_eth_data = 0,
|
||||
data_type_cmd,
|
||||
data_type_resp,
|
||||
data_type_status,
|
||||
}
|
||||
app_data_type_typedef;
|
||||
|
||||
struct spi_data_packet
|
||||
{
|
||||
uint32_t data_len;
|
||||
uint32_t data_type;
|
||||
char buffer[SPI_MAX_DATA_LEN];
|
||||
};
|
||||
|
||||
/********************************* RW009 **************************************/
|
||||
|
||||
/* option */
|
||||
#define RW009_CMD_TIMEOUT (RT_TICK_PER_SECOND*3)
|
||||
#define SSID_NAME_LENGTH_MAX (32)
|
||||
#define PASSWORD_LENGTH_MAX (64)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MODE_STATION=0,
|
||||
MODE_SOFTAP=1,
|
||||
} wifi_mode_t;
|
||||
|
||||
typedef struct _rw009_ap_info
|
||||
{
|
||||
char ssid[SSID_NAME_LENGTH_MAX];
|
||||
uint8_t bssid[8]; // 6byte + 2byte PAD.
|
||||
int rssi; /* Receive Signal Strength Indication in dBm. */
|
||||
uint32_t max_data_rate; /* Maximum data rate in kilobits/s */
|
||||
uint32_t security; /* Security type */
|
||||
uint32_t channel; /* Radio channel that the AP beacon was received on */
|
||||
} rw009_ap_info;
|
||||
|
||||
typedef struct _rw009_cmd_init
|
||||
{
|
||||
uint32_t mode;
|
||||
} rw009_cmd_init;
|
||||
|
||||
typedef struct _rw009_resp_init
|
||||
{
|
||||
uint8_t mac[8]; // 6byte + 2byte PAD.
|
||||
uint8_t sn[24]; // serial.
|
||||
char version[16]; // firmware version.
|
||||
} rw009_resp_init;
|
||||
|
||||
typedef struct _rw009_cmd_easy_join
|
||||
{
|
||||
char ssid[SSID_NAME_LENGTH_MAX];
|
||||
char passwd[PASSWORD_LENGTH_MAX];
|
||||
} rw009_cmd_easy_join;
|
||||
|
||||
typedef struct _rw009_cmd_join
|
||||
{
|
||||
uint8_t bssid[8]; // 6byte + 2byte PAD.
|
||||
char passwd[PASSWORD_LENGTH_MAX];
|
||||
} rw009_cmd_join;
|
||||
|
||||
typedef struct _rw009_cmd_rssi
|
||||
{
|
||||
uint8_t bssid[8]; // 6byte + 2byte PAD.
|
||||
} rw009_cmd_rssi;
|
||||
|
||||
typedef struct _rw009_cmd_softap
|
||||
{
|
||||
char ssid[SSID_NAME_LENGTH_MAX];
|
||||
char passwd[PASSWORD_LENGTH_MAX];
|
||||
|
||||
uint32_t security; /* Security type. */
|
||||
uint32_t channel; /* Radio channel that the AP beacon was received on */
|
||||
} rw009_cmd_softap;
|
||||
|
||||
typedef struct _rw009_resp_join
|
||||
{
|
||||
rw009_ap_info ap_info;
|
||||
} rw009_resp_join;
|
||||
|
||||
struct rw009_cmd
|
||||
{
|
||||
uint32_t cmd;
|
||||
uint32_t len;
|
||||
|
||||
/** command body */
|
||||
union
|
||||
{
|
||||
rw009_cmd_init init;
|
||||
rw009_cmd_easy_join easy_join;
|
||||
rw009_cmd_join join;
|
||||
rw009_cmd_rssi rssi;
|
||||
rw009_cmd_softap softap;
|
||||
} params;
|
||||
};
|
||||
|
||||
struct rw009_resp
|
||||
{
|
||||
uint32_t cmd;
|
||||
uint32_t len;
|
||||
|
||||
int32_t result; // result for CMD.
|
||||
|
||||
/** resp Body */
|
||||
union
|
||||
{
|
||||
rw009_resp_init init;
|
||||
rw009_ap_info ap_info;
|
||||
} resp;
|
||||
};
|
||||
|
||||
#define RW009_CMD_INIT 128
|
||||
#define RW009_CMD_SCAN 129
|
||||
#define RW009_CMD_JOIN 130
|
||||
#define RW009_CMD_EASY_JOIN 131
|
||||
#define RW009_CMD_RSSI 132
|
||||
#define RW009_CMD_SOFTAP 133
|
||||
|
||||
/** cond !ADDTHIS*/
|
||||
#define SHARED_ENABLED 0x00008000
|
||||
#define WPA_SECURITY 0x00200000
|
||||
#define WPA2_SECURITY 0x00400000
|
||||
#define WPS_ENABLED 0x10000000
|
||||
#define WEP_ENABLED 0x0001
|
||||
#define TKIP_ENABLED 0x0002
|
||||
#define AES_ENABLED 0x0004
|
||||
#define WSEC_SWFLAG 0x0008
|
||||
/** endcond */
|
||||
/**
|
||||
* Enumeration of Wi-Fi security modes
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SECURITY_OPEN = 0, /**< Open security */
|
||||
SECURITY_WEP_PSK = WEP_ENABLED, /**< WEP Security with open authentication */
|
||||
SECURITY_WEP_SHARED = ( WEP_ENABLED | SHARED_ENABLED ), /**< WEP Security with shared authentication */
|
||||
SECURITY_WPA_TKIP_PSK = ( WPA_SECURITY | TKIP_ENABLED ), /**< WPA Security with TKIP */
|
||||
SECURITY_WPA_AES_PSK = ( WPA_SECURITY | AES_ENABLED ), /**< WPA Security with AES */
|
||||
SECURITY_WPA2_AES_PSK = ( WPA2_SECURITY | AES_ENABLED ), /**< WPA2 Security with AES */
|
||||
SECURITY_WPA2_TKIP_PSK = ( WPA2_SECURITY | TKIP_ENABLED ), /**< WPA2 Security with TKIP */
|
||||
SECURITY_WPA2_MIXED_PSK = ( WPA2_SECURITY | AES_ENABLED | TKIP_ENABLED ), /**< WPA2 Security with AES & TKIP */
|
||||
|
||||
SECURITY_WPS_OPEN = WPS_ENABLED, /**< WPS with open security */
|
||||
SECURITY_WPS_SECURE = (WPS_ENABLED | AES_ENABLED), /**< WPS with AES security */
|
||||
|
||||
SECURITY_UNKNOWN = -1, /**< May be returned by scan function if security is unknown. Do not pass this to the join function! */
|
||||
|
||||
SECURITY_FORCE_32_BIT = 0x7fffffff /**< Exists only to force wiced_security_t type to 32 bits */
|
||||
} security_t;
|
||||
|
||||
/* porting */
|
||||
extern void spi_wifi_hw_init(void);
|
||||
extern void spi_wifi_int_cmd(rt_bool_t cmd);
|
||||
extern rt_bool_t spi_wifi_is_busy(void);
|
||||
|
||||
/* export API. */
|
||||
extern rt_err_t rt_hw_wifi_init(const char *spi_device_name,wifi_mode_t mode);
|
||||
extern int32_t rw009_rssi(void);
|
||||
extern rt_err_t rw009_join(const char * SSID, const char * passwd);
|
||||
extern rt_err_t rw009_softap(const char * SSID, const char * passwd,uint32_t security,uint32_t channel);
|
||||
|
||||
#endif // SPI_WIFI_H_INCLUDED
|
Reference in New Issue
Block a user