21603|8

5

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

STM32 Marvell8686 SPI 接口跑WIFI [复制链接]

前几天见看到网友用STM32跑WIFI,觉得这东西很有意思,所以自己也想开始搞一个。
由于刚刚开始现在只发送命令扫描无线节点 ,所以想开个帖子记录一下开发过程。虽然还没搞好,但是既然有网友搞通过因此我也还是很有信心的,希望能坚持走下去,同时也希望大家多多讨论。

我采用的方案同样也是STM32 + Marvell88w8686 的组合。
通讯方式采用SPI方式,虽然比SDIO慢了许多,但是调试和接线比较方便。

目前已经实现了固件的下载和CMD命令发送。
固件下载主要参考linux下的if_spi.c中固件下载和手册中的固件下载部分
1.首先将设备引导代码写入IF_SPI_CMD_WRITEBASE_REG(0x14)寄存器
2.设置IF_SPI_CARD_INT_STATUS_REG寄存器时期进入等待固件下载状态
3.等待IF_SPI_CARD_INT_STATUS_REG寄存器返回
4.将固件数据写入命令读写寄存器(0x18)中
5.err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);清空寄存器
上面几个步骤是下载第一个固件也就是helper.bin的一个大致流程,详细的可以参考if_spi_prog_helper_firmware函数,其实移植起来也是相当简单的。

接下来就是下载第二个固件和检查固件是否成功并运行。也就是校验0x38寄存器中是不是0x88888888。

若固件校验下载成功并运行下面的工作就相对流程化了,但是工作量可不小哦。
大致上可分为CMD的发送和接收与数据的发送和接收
命令的发送主要是由802.11控制协议转换成8686的控制命令,其数据结构基本上都在host.h中
struct cmd_ds_802_11_scan {
    struct cmd_header hdr;

    uint8_t bsstype;
    uint8_t bssid[ETH_ALEN];
    uint8_t tlvbuffer[0];
} __packed;

struct cmd_ds_802_11_scan_rsp {
    struct cmd_header hdr;

    __le16 bssdescriptsize;
    uint8_t nr_sets;
    uint8_t bssdesc_and_tlvbuffer[0];
} __packed;

是扫描命令的发送和接收的数据结构。

数据的发送和接受没什么说的,也就是普通的802.3包,LINUX驱动中tx.c中lbs_process_rxed_packet 函数将其转换成sk_buff来交与LINUX网络子系统进行处理

在8686的LINUX驱动大致过程为:

lbs_spi_thread 一个SPI线程负责while(1)轮训卡上是否有读取的CMD或者DATA,如果是DATA将调用if_spi_c2h_data如果是CMD将调用if_spi_c2h_cmd

if_spi_c2h_data 函数负责将卡中的数据转到主机中,然后调用lbs_process_rxed_packet

err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len); 读取卡中有多数据需要读取

err = spu_read(card, IF_SPI_DATA_RDWRPORT_REG, data, ALIGN(len, 4));开始读取数据 

lbs_process_rxed_packet 函数负责将收到的数据转换成802.3格式的包。

 

lbs_thread 负责传输数据或命令的线程 ,他会调用lbs_execute_next_command或者if_spi_host_to_card(hw_host_to_card*)

if_spi_host_to_card 从主机到卡上的数据lbs_submit_command和lbs_thread都会调用他

lbs_execute_next_command 调用 lbs_submit_command

static struct cfg80211_ops lbs_cfg80211_ops = {//负责控制的OPS

lbs_process_command_response 负责处理命令的返回,通过内核线程锁来实现同步的,由lbs_thread调用,一般是在调用lbs_execute_next_command后调用


例如扫描命令的发送流程
//开始扫描
lbs_scan_worker 执行扫描命令,在其中中创建CMD命令格式,首先,分配LBS_SCAN_MAX_CMD_SIZE大小的空间

cmd_ctrl_node cmdnode 中 cmdnode->cmdbuf 是要被发送的数据cmd->size时要被发送的大小

cmd_header 在 host.h中,是命CMD的头对应PDF p62
__lbs_cmd_async 负责填充一个CMD头

lbs_add_ssid_tlv ,lbs_add_channel_list_tlv 两是构造BODY的函数

cmd_ds_802_11_scan SCAN命令的BODY




此帖出自stm32/stm8论坛

最新回复

你是联系方式里那个刘工? 我曾买过一个板子   详情 回复 发表于 2015-1-12 09:13
点赞 关注
 

回复
举报

1

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
新手正好要搞这个,兄弟能聊聊吗? qq: 47358117
此帖出自stm32/stm8论坛
 
 

回复

5

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
                                             

[ 本帖最后由 stopfan 于 2012-2-4 11:35 编辑 ]
此帖出自stm32/stm8论坛
 
 

回复

5

帖子

0

TA的资源

一粒金砂(中级)

4
 

回复 沙发 delphips 的帖子

可以,过年这段时间没怎么搞,只是搞到了正常搜索 和连接无加密的 AP Q:7914703
此帖出自stm32/stm8论坛
 
 
 

回复

2

帖子

0

TA的资源

一粒金砂(初级)

5
 

我也打算做

我也打算做这个,能探讨下吗,我加你QQ了
此帖出自stm32/stm8论坛
 
 
 

回复

49

帖子

0

TA的资源

一粒金砂(初级)

6
 
近期也有此工程。
此帖出自stm32/stm8论坛
 
 
 

回复

5

帖子

0

TA的资源

一粒金砂(中级)

7
 

STM23 + 8686 WIFI 数据连通的具体实现

过年的这段时间没时间搞这个,最近终于腾出一点时间来把数据链路层次给跑通了。TCP/IP 用的是UIP。
是我实现数据接收具体细节:
1.先从 0x28 寄存器读取8686固件所接收到的数据长度
2.然后从 0x24 寄存器中读取指定长度的数据

int recv_data(u8 * recv_buf , u16 * recv_len){
gspi_card_rec_p p;
u16 datalen = 0x0;

//read data len;
#define IF_SPI_SCRATCH_1_REG 0x28
while(datalen == 0x0)
{
gspi_read_reg(p, IF_SPI_SCRATCH_1_REG, &datalen);
}
//printf("RECV DATA LEN : %d \r\n",datalen);
gspi_read_data_direct(p,recv_buf,DATA_RDWRPORT_REG,datalen);

if (recv_len != NULL)
*recv_len = datalen ;
return 0x0;
}

发送也很简单,直接把数据写入0x24 寄存器中就可以了
int send_data(u8 * data , u16 len)
{
gspi_card_rec_p p;
#define IF_SPI_DATA_RDWRPORT_REG 0x24 /* Read/Write data port reg */
gspi_write_data_direct(p,data,IF_SPI_DATA_RDWRPORT_REG,len);//send msg
return 0x0;
}

下面再说接收和发送到的数据包格式
8686接收到的数据格式一般是802.3snmp格式的(默认情况下,其实是可以设置的),而我移植的UIP能够识别的是EthII格式的。不过这没有关系,我们只要自己转换就可以了(其实就是把有用数据摘取出来,忽略无效数据)

int MrlRecvEthData(u8 * buf , u16 * len)
{
int ret = 0;
//struct net_device *dev = priv->dev;
struct rxpackethdr *p_rx_pkt;
struct rxpd *p_rx_pd;
int hdrchop;
struct ethhdr *p_ethhdr;
static const u8 rfc1042_eth_hdr[] = {
0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00
};

u8 *__packet = (u8*)my_malloc();
u16 __packet_len = 0;

u8 *__packet_p = __packet;
u8 *__packet_end_p = __packet;
u8 *buf_p = buf;

u16 u16_i = 0x0;


recv_data(__packet,&__packet_len);
__packet_end_p += __packet_len;

if (__packet_len <= 0)
goto done;

p_rx_pd = (struct rxpd *) __packet;
#if 0
printf("DEBUG RX: ");
printf("NULL");
printf("\r\n");
#endif

p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd +
le32_to_cpu(p_rx_pd->pkt_ptr));


if (__packet_len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
goto done;
}

#if 0

debug_hex("RX Data: Dest MAC:", p_rx_pkt->eth803_hdr.dest_addr,
sizeof(p_rx_pkt->eth803_hdr.dest_addr));
debug_hex("RX Data: Src MAC:", p_rx_pkt->eth803_hdr.src_addr,
sizeof(p_rx_pkt->eth803_hdr.src_addr));


printf("RECV 80211 DATA:");
for(u16_i=0x0;u16_i<__packet_len;u16_i++)
{
printf("[0x%02x]",__packet[u16_i]);
}
printf("\r\n");
#endif

*len = 0x0;

// start copy ethdata to buf from 80211 data;
__packet_p = (u8*)p_rx_pkt;
memcpy(buf_p,__packet_p,12);

buf_p += 12;
__packet_p += 12 ;
(*len) += 12;


__packet_p += 8 ;
memcpy(buf_p,__packet_p,(__packet_end_p - __packet_p));
buf_p = buf_p+(__packet_end_p - __packet_p);
(*len) = (*len) + (__packet_end_p - __packet_p);
__packet_p = __packet_end_p;

#if 0
printf("ETH DATA:");
for(u16_i=0x0;u16_i<(*len);u16_i++)
{
printf("[0x%02x]",buf[u16_i]);
}
printf("\r\n");
#endif

done:
my_free(__packet);
return ret;
}

发送的数据格式一把情况下就是 struct txpd + EthII 数据包就行了。

int MrlSendEthData(u8 * buf , u16 len)
{
u16 u16_i , pkt_len;

u8 * p802x_hdr = buf;

struct txpd * __txpd = (struct txpd *)my_malloc();
memset(__txpd,0x0,sizeof(struct txpd));
pkt_len = len;

if (0)
{/*if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)*/}
else
{memcpy(__txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);};


__txpd->tx_packet_length = cpu_to_le16(pkt_len);
__txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));

//lbs_mesh_set_txpd(priv, dev, txpd);
//insert 8
//memcpy(&__txpd[1], p802x_hdr, le16_to_cpu(__txpd->tx_packet_length));
memcpy(&__txpd[1], p802x_hdr, le16_to_cpu(__txpd->tx_packet_length));

#if 0
printf("SEND ETH DATA:");
for(u16_i=0;u16_i {
printf("[0x%02x]",buf[u16_i]);
}
printf("\r\n");
#endif
len = len + sizeof(struct txpd);
#if 0
printf("SEND 80211 DATA:");
for(u16_i=0;u16_i {
printf("[0x%02x]",((u8*)__txpd)[u16_i]);
}
printf("\r\n");
#endif


//while(1);
send_data((u8*)__txpd,len);

my_free(__txpd);

return 0;
}

这样基本就完成了,以太网数据的发送和接收。这里需要注意一点,就是设置给固件的MAC地址一定要和设置给UIP的MAC地址相同,不然只能接收到广播包,我就在这里兜了很大一圈子。

接下来的工作就是加密部分的移植了,WEP还好说,WPA估计难度会很大,希望自己能够坚持下去
此帖出自stm32/stm8论坛
 
 
 

回复

5

帖子

0

TA的资源

一粒金砂(中级)

8
 
STM32 驱动 WIFI 已经完善,欢迎大家光临我的小店
下面是地址 新动力
newpower99点taobao点com
此帖出自stm32/stm8论坛
 
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

9
 
stopfan 发表于 2012-11-22 13:29
STM32 驱动 WIFI 已经完善,欢迎大家光临我的小店
下面是地址 新动力
newpower99点taobao点com

你是联系方式里那个刘工?

我曾买过一个板子
此帖出自stm32/stm8论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表