1. 程式人生 > >STM8S---選項位元組(Option Byte)寫操作之IO複用

STM8S---選項位元組(Option Byte)寫操作之IO複用

功能實現目標

  通過對選項位元組的寫操作來實現TIM2的CH3通道的PWM輸出IO複用,可以設定為PA3或者PD2輸出。
通過STVP方式操作連結

選項位元組

  選項位元組包括晶片硬體特性的配置和儲存器的保護資訊,這些位元組儲存在儲存器中一個專用的塊內。除了ROP(讀出保護)位元組,每個選項位元組必須被儲存兩次,一個是通常的格式(OPTx)和一個用來備份互補格式的(NOPTx)。選項位元組可以通過應用程式在IAP模式下修改,但是ROP選項只能在ICP模式(通過SWIM)下被修改。有關SWIM程式設計過程的內容可以參考STM8S快閃記憶體程式設計手冊(PM0051)和STM8 SWIM通訊協議和除錯模組使用者手冊(UM0470)。
  不同的晶片的選項位元組大小不一樣,具體的可以參考晶片資料手冊。如用STM8S103F3來舉例,選項位元組如下:

選項位元組

  STM8S103F對於20腳封裝的產品的複用功能重定義位:

STM8S103F複用功能重定義位

  由此可知我們要將OPT2位元組中的AFR1位進行寫操作,通過寫0,則埠A3複用功能TIM2_CH3,通過寫1,埠D2複用功能TIM2_CH3。接下來通過程式實現這個功能,可以修改AFR1的值來看PWM輸出是否切換了管腳,如果能,則是實現了寫操作。
  選項位元組存放在EEPROM中,所以可以通過讀寫EEPROM一樣的操作方式來修改選項位元組。應用程式可以直接向目標地址進行寫操作。地址從上面的圖中我們已經知道了:0x4803,0x4804。暫存器的配置可以查閱參考手冊(RM0016)。
  相關暫存器操作:

FLASH_CR2

FLASH_NCR2

測試程式實現

  注意:實現程式擦寫Option Bytes時,不能執行應用程式,否則會出現錯誤!不過還是覺得這點麻煩啊,還不如用STVP來擦寫,要是能夠放在應用程式中共存來擦寫就好了,用程式實現複用就這麼麻煩嗎?希望能探索找到好的方法,最後只找到了個不靠譜的,就是在擦寫後加上延時,但是這個時管用時不管用。還是再查閱資料看看是怎麼回事?

ST Visual Develop

  但是用STVP擦寫時又遇到了這個錯誤:

Error : Error on Option Bytes (complementary bytes). Reprogram Option Bytes of device
Error : < OPTION BYTE verifying failed.

  用STVP來擦寫Option Bytes了,先將ROP設定為ON,然後再擦寫Option Bytes,會出現兩個提示框,選擇是(Y),再之後又將ROP設定為OFF,再次擦寫Option Bytes,則又可以用STVD通過stlink來燒寫程式並模擬了。

STVP program option bytes

T1

T2

測試程式:
/* MAIN.C file
Functons    :   操作option byte位元組,設定IO複用,來修改TIM2的CH3通道PWM輸出管腳PA3 or PD2
Date        :   2015年7月22日
Author      :   yicm
Notes       :   
 */

#include<stm8s003f3p.h>

void CLK_init(void)
{
    CLK_ICKR |= 0X01;           //使能內部高速時鐘 HSI
    CLK_CKDIVR = 0x08;          //16M內部RC經2分頻後系統時鐘為8M
    while(!(CLK_ICKR&0x02));    //HSI準備就緒 
    CLK_SWR=0xe1;               //HSI為主時鐘源 
}

void Init_GPIO(void)
{
    /*設定為推輓輸出,PD2接了LED燈*/
    PD_DDR |= 0X04;             //設定PD2埠為輸出模式
    PD_CR1 |= 0X04;             //設定PD2埠為推輓輸出模式
    PD_CR2 &= 0XFD;

    PA_DDR |= 0X08;             //設定PA3埠為輸出模式
    PA_CR1 |= 0X08;             //設定PA3埠為推輓輸出模式
    PA_CR2 |= 0XF7;
}

void Init_Tim2(void)
{
    TIM2_CCMR3 |=   0X70;   //設定定時器2三通道(PD2)輸出比較三模式
    TIM2_CCMR3 |= 0X04;     //輸出比較3預裝載使能

    TIM2_CCER2 |= 0x03;     //通道3使能,低電平有效,配置為輸出

    // 初始化時鐘分頻器為1,即計數器的時鐘頻率為Fmaster=8M/64=0.125MHZ
    TIM2_PSCR = 0X07;   
    //初始化自動裝載暫存器,決定PWM 方波的頻率,Fpwm=0.125M/62500=2HZ
    TIM2_ARRH = 62500/256;
    TIM2_ARRL = 62500%256;
    //初始化比較暫存器,決定PWM 方波的佔空比:5000/10000 = 50%
    TIM2_CCR3H = 31250/256;
    TIM2_CCR3L = 31250%256;


    //啟動計數;更新中斷失能
    TIM2_CR1 |= 0x81;
    //TIM2_IER |= 0x00;        
}

void Write_Option_Byte(void)
{   
    unsigned char opt[6] = {0,0,0x00,0,0,0};

    /*解鎖Flash*/
    do
    {
        FLASH_DUKR = 0xAE;
        FLASH_DUKR = 0x56;      
    }
    while(!(FLASH_IAPSR & 0X08));

    /*對選項位元組進行寫操作使能*/
    FLASH_CR2 = 0X80;
    /*互補控制暫存器*/
    FLASH_NCR2 = 0X7F;
    /*寫操作,0x02:PD2。0x00:PA3*/
    *((unsigned char *)0x4800) = opt[0];

    *((unsigned char *)0x4801) = opt[1];
    *((unsigned char *)0x4802) = ~opt[1];

    *((unsigned char *)0x4803) = opt[2];
    *((unsigned char *)0x4804) = ~opt[2];

    *((unsigned char *)0x4805) = opt[3];
    *((unsigned char *)0x4806) = ~opt[3];

    *((unsigned char *)0x4807) = opt[4];
    *((unsigned char *)0x4808) = ~opt[0];

    *((unsigned char *)0x4809) = opt[5];
    *((unsigned char *)0x480A) = ~opt[5];  

    /*等待寫結束*/
    while(!(FLASH_IAPSR & 0x04));
}

main()
{
    int i;

    Write_Option_Byte();    //執行程式時,遮蔽  
    for(i=0;i<10000;++i);   //延時效果,有時加上延時,能夠使擦寫和應用程式同時不遮蔽也能管用

    CLK_init();             //擦寫時遮蔽,否則下次stlink模擬時會出錯
    Init_GPIO();            //擦寫時遮蔽,否則下次stlink模擬時會出錯
    Init_Tim2();            //擦寫時遮蔽,否則下次stlink模擬時會出錯
    while (1);
}