關於DSP2812控制W5500的程式解讀,3.22

核磁專案3月22日@TOC

CMD檔案的解讀

將此引腳置為低電平,表示為微電腦模式,向量表指向Boot Rom。

1
    ROM              : origin = 0x3FF000, length = 0x000FC0     /* boot ROM available if MP/MCn=0 */

程式從這兒開始。
再看看儲存器映像。
分配程式空間

1
PRAMH0     : origin = 0x3f8000, length = 0x003000boot ROM available if MP/MCn=0 */

但是存在一個問題,就是我佔用了保留的空間,因為CMD命令顯示程式空間不夠,很可能會出問題。如果出問題了,第一個解決辦法是,將程式空間放到外擴RAM Zone2中,因為上傳的資料花不了那麼空間;第二個辦法就是換晶片,換個RAM空間多一點的晶片。

PAGE 1 就是分配資料空間,注意要對應起來,外設和一些C的資料空間,一般模板是兩個CMD檔案,我只用了一個檔案。

如果說 MEMORY 命令是定義每個東西的位置。那麼SECTION命令就是,將所有相關的程式,資料分配到固定位置。

main函式的解讀

一些加標頭檔等等的操作不在贅述。包括對資料夾的設定,什麼檔案怎麼放等等。

首先定義一些網路相關的變數

1
2
3
4
5
6
uint8 server_ip[4]={<!-- -->192,168,1,101};
uint16 server_port=5000;
uint16 local_port=6000;
uint16 len=0;
uint8 buffer[2048];
boot ROM available if MP/MCn=0 */

網路客戶端連接埠網路客戶端ip本地連接埠
len代表socket快取裡面還剩餘的空間,buffer陣列存的是從W5500裡面讀取到的資料。這個下文再分析

對系統的初始化

關看門狗;

1
2
3
4
5
6
void DisableDog(void)
{<!-- -->
    EALLOW;
    SysCtrlRegs.WDCR= 0x0068;
    EDIS;
}

初始化鎖相環,定義時鐘;

1
2
3
      EALLOW;
      SysCtrlRegs.PLLCR.bit.DIV = val;
      EDIS;

Val 就是一個數,4-bit PLL Select。時鐘=外部時鐘*Val/2

初始化外設時鐘

1
2
3
4
5
     SysCtrlRegs.HISPCP.all = 0x0000;
     SysCtrlRegs.LOSPCP.all = 0x0002;
     SysCtrlRegs.PCLKCR.bit.EVAENCLK=1;
     SysCtrlRegs.PCLKCR.bit.EVBENCLK=1;
     SysCtrlRegs.PCLKCR.bit.SPIENCLK=1;

這些外設時鐘一般都是預設的高速還是低速時鐘,高速和低速時鐘是透過主頻分頻而來。如上程式碼所示,高速不分頻,低速分兩次,就是除以4.本專案晶振為10M,主頻50M,高速50M,低速12,5M.事件A,B都是高速。spi為低速。此處存在一個問題,中斷的時鐘開不開。

對SPI的GPIO口的初始化

硬體如圖。四個介面分別為F1,F2,F3,F4

1
2
3
4
5
6
7
8
9
10
    void InitSpiaGpio(void)
    {<!-- -->

       EALLOW;
       GpioMuxRegs.GPFMUX.bit.SPISIMOA_GPIOF0=1;
       GpioMuxRegs.GPFMUX.bit.SPISOMIA_GPIOF1=1;
       GpioMuxRegs.GPFMUX.bit.SPICLKA_GPIOF2=1;
       GpioMuxRegs.GPFMUX.bit.SPISTEA_GPIOF3=1;
       EDIS;
    }

程式直接如圖,2812貌似不用設定方向和上拉什麼的,只需要配置為SPI的介面,這個存疑。也就是他的復用。配置為普通IO的話,暫存器寫0,復用外設則寫1。

對SPI的重定IO口的初始化

存在疑惑,它的中斷需不需要用上,由圖,gpioa9,配置他的io和方向,是一個輸出。程式碼如圖

1
2
3
4
5
6
7
void gpio_config(void)
{<!-- -->
     EALLOW;
     GpioMuxRegs.GPAMUX.bit.CAP2Q2_GPIOA9=0;//GPA9 RSTn,設定為i/o
     GpioMuxRegs.GPADIR.bit.GPIOA9= 1;//方向輸出;1:輸出;0:輸入
     EDIS;
}

然後是一些關中斷的操作

對SPI本身的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
void spi_init()
{<!-- -->

    SpiaRegs.SPICCR.bit.SPISWRESET = 0;//重定SPI
    SpiaRegs.SPICCR.all = 0x000F;       //0000  0000  0000 1111
                                                //0~3,位元組控制為16位;4,禁止SPI回送;5,保留;6,上升輸出,下降輸入;7,重定
    SpiaRegs.SPICTL.all = 0x0006;       // 00000000 0000 0110   中斷無效,使能發送引腳,主機模式  無相位延時 禁止中斷
//  Enable master mode, normal phase, // enable talk, and SPI int disabled.
    SpiaRegs.SPISTS.all = 0x0000;       //溢位中斷,禁止SPI中斷; 重定系統
    SpiaRegs.SPIBRR = 0x0009;           //SPI波特率=12.5M/10=1.25MHZ;0000 1001
    SpiaRegs.SPIPRI.bit.FREE = 1;       //Set so breakpoints don't disturb xmission
    SpiaRegs.SPICCR.bit.SPISWRESET = 1;
}

這兒就需要查暫存器進行一個修改了,DSP做主機,W5500做從機
波特率設定
SPICCR暫存器:此暫存器0~3位決定在一個移送序列中,作為單個字元被移動的位的數量這裡我們設定為16位。
此暫存器的第6位代表的時鐘極性,透過兩個位才能確定SPI發送和接收的方式。一個是SPICCR.CLKPOLARITY,一個是SPCTL.CLK_PHASE。共有四種方式。但是W5500只支援兩種,0和3。問題來了,主機和從機的模式是否一致,還是只需要設定主機的模式。我認為應該只用設計主機的模式,所以我設定為模式0。上升沿發送,下降沿接收,無延時
SPIPRI 這個設定為x 1 ,忽略了中斷,可能會有問題。

重定W5500

1
2
3
4
5
6
7
void Reset_W5500(void)//reset
{<!-- -->
    GpioDataRegs.GPADAT.bit.GPIOA9 = 0;
    delay_loop();
    GpioDataRegs.GPADAT.bit.GPIOA9 = 1;
    delay_loop();
}

設定預設網路相關的變數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void set_default(void)                                  // 設定預設MAC、IP、GW、SUB、DNS
{<!-- -->  
  uint8 mac[6]={<!-- -->0x00,0x08,0xdc,0x11,0x11,0x11};
  uint8 lip[4]={<!-- -->192,168,1,88};
  uint8 sub[4]={<!-- -->255,255,255,0};
  uint8 gw[4]={<!-- -->192,168,1,1};
  uint8 dns[4]={<!-- -->8,8,8,8};
  memcpy(ConfigMsg.lip, lip, 4);
  //printf("lip: %d.%d.%d.%d
",lip[0],lip[1],lip[2],lip[3]);
  memcpy(ConfigMsg.sub, sub, 4);
  //printf("sub: %d.%d.%d.%d
",sub[0],sub[1],sub[2],sub[3]);
  memcpy(ConfigMsg.gw,  gw, 4);
  //printf("gw: %d.%d.%d.%d
",gw[0],gw[1],gw[2],gw[3]);
  memcpy(ConfigMsg.mac, mac,6);

  memcpy(ConfigMsg.dns,dns,4);
  //printf("dns: %d.%d.%d.%d
",dns[0],dns[1],dns[2],dns[3]);

  ConfigMsg.dhcp=0;
  ConfigMsg.debug=1;
  ConfigMsg.fw_len=0;
 
  ConfigMsg.state=NORMAL_STATE;
  ConfigMsg.sw_ver[0]=FW_VER_HIGH;
  ConfigMsg.sw_ver[1]=FW_VER_LOW;
}

除錯網路的時候肯定得改一些IP地址什麼的。

設定網路,

1
2
3
4
5
向W5500寫入什麼東西,mac,sub,gw lip。
值得關注的是對Socket的初始化,將他的Socket 0 調成16K
程式碼:
uint8 txsize[MAX_SOCK_NUM] = {<!-- -->16,0,0,0,0,0,0,0};        // 選擇8個Socket每個Socket發送快取的大小,在w5500.c的void sysinit()有設定過程
uint8 rxsize[MAX_SOCK_NUM] = {<!-- -->16,0,0,0,0,0,0,0};        // 選擇8個Socket每個Socket接收快取的大小,在w5500.c的void sysinit()有設定過程

while1程式

首先是一個Switch
去讀取Sn_SR暫存器的值,看他是否為0x13
代表為TCP工作模式。然後根據連接埠和IP連接。

1
2
            case SOCK_INIT:
                    connect(0, server_ip,server_port);

然後再讀,是否為0x17
代表連接成功,進行下一步。
讀取該位,Sn_IR_CON,表示建立連線。
讀取Sn_RX_RSR,len=getSn_RX_RSR(0);看他還有多少空間
Sn_RX_RSR 顯示了 Socket n 接收快取中已接收和儲存的資料大小。
len不為0,

1
2
3
4
5
6
7
                    if(len>0)
                    {<!-- -->
                        //memset(buffer,'0',strlen(buffer));
                        recv(0,buffer,len);
                        send(0,buffer,len);

                    }

這樣就把w5500裡面的資料,存到了buffer陣列裡面,然後在sendbuffer裡面的資料到W5500.就完成了一個LOOPback的迴環。