UMEHOSHI ITA TOP PAGE COMPUTER SHIEN LAB
#ifndef _MY_UTIL_H /* Guard against multiple inclusion */ #define _MY_UTIL_H // 【2023-4】でファイルを追加 // EEPROM 制御関数 unsigned int NVM_unlock (unsigned int nvmop);//ロック解除,NVMCON設定シーケンス unsigned int NVM_erase_page(unsigned int address);// address指定で1ページ(1024バイト)を0xffに消去 unsigned int NVM_write_word (unsigned int address, unsigned int data);//addressの位置にdataワードを書き込む int get_version(); // バージョンを返す。 void power_on_start(); #endif /* _MY_UTIL_H */
#include <xc.h>
#include <proc/p32mx270f256b.h>
#include <stdlib.h>
#include "my_util.h"
#include "common.h"
// 参考: 60001121G_JP.pdf の不揮発性メモリ ( NonVolatile Memory )CONTROL
unsigned int NVM_unlock (unsigned int nvmop)//ロック解除,NVMCON 設定シーケンス
{
unsigned int status;
asm volatile ("di %0" : "=r" (status));// Disable all Interrupts
NVMCON = nvmop; // NVM(SFR)Flashプログラミング制御レジスタ設定
NVMKEY = 0xAA996655;//EEPROMの意図しない書き込みなどを防ぐ指定シーケンス1
NVMKEY = 0x556699AA;//EEPROMの意図しない書き込みなどを防ぐ指定シーケンス2
NVMCONSET = 0x8000;// Start the operation using the Set Register
while (NVMCONbits.WR){
;// Wait for operation to complete
}
if (status & 0x00000001){
asm volatile ("ei");// Restore Interrupts
} else {
asm volatile ("di");
}
NVMCONCLR = 0x0004000; // Disable NVM write enable
return (NVMCON & 0x3000);// Return WRERR and LVDERR Error Status Bits
// bit13:WRERRのbitが1の時、プログラミングまたは消去シーケンスは正常に完了しなかった
// bit12:LVDERRのbitが1の時、WRERRがセットされた場合、データは破損した可能性がある
}
// UMEHOSHI_ITAで使っているのはPIC32MX270F256Bでプログラムフラシュの
// kseg0_program_memは、0x9D000000より0x9D03F000の範囲
// 0x9D020000?をこの引数にして消去可能(ページ消去で消せるのは1024バイト)
// 0x9D03F000-0x9D020000=126976が一般ユーザが書き込める範囲となる
// 次の消去アドレスは0x9D020200、次が0x9D020400で、0x9d03ee00まで指定可
unsigned int NVM_erase_page(unsigned int address)
{
unsigned int res;
if( address < 0xB0000000U) address += +0x20000000U;
NVMADDR = (unsigned int) address; // 書き込みアドレス(書き込み位置)
// 書き込みモードの指定
// 0001 - 4バイト単位で書き込む
// 0011 - 512バイト単位で書き込む(指定アドレスは512の倍数)
// 0100 - 512バイト消去ページ消去動作: NVMADDRで選択したページを消去する
// 0101 - プログラム領域をすべて消去(ブート領域でのみ実行可)
//NVMCONbits.NVMOP = 0b0001; // WordWrite
//NVMCONbits.WREN = 1;// 書き込みの許可(bit 14 WREN: 書き込みイネーブルビット)
//0x4001;// NVM(SFR)Flashプログラミング制御レジスタ設定
res = NVM_unlock (0x4000);//WRERR: 書き込みエラービットをクリア
res |= NVM_unlock (0x4004);// メモリ初期化のページ消去動作
return res;// Return Result(ゼロが戻れば成功)
}
// PIC32MX270F256Bでプログラムフラシュの kseg0_program_memは、0x9D000000より
// 0x9D03F000の範囲で、dataの1ワード(32bit)を、addressの位置に書き込む。
unsigned int NVM_write_word (unsigned int address, unsigned int data)
{
unsigned int res;
NVMDATA = data; // 書き込みデータ
asm("nop");
if( address < 0xB0000000U) address += +0x20000000U;
NVMADDR = address; // 書き込みアドレス(書き込み位置)
// 書き込みモードの指定
// 0001 - 4バイト単位で書き込む
// 0011 - 512バイト単位で書き込む(指定アドレスは512の倍数)
// 0100 - 4KB単位で消去
// 0101 - プログラム領域をすべて消去(ブート領域でのみ実行可)
//NVMCONbits.NVMOP = 0b0001; // WordWrite
//NVMCONbits.WREN = 1;// 書き込みの許可(bit 14 WREN: 書き込みイネーブルビット)
//0x4001;// NVM(SFR)Flashプログラミング制御レジスタ設定
res = NVM_unlock (0x4001);
return res;// Return Result
}
// パワーオン時のEEPROM内容で指示する起動関数を呼び出す処理(init_interrupt内で呼ぶ)
// パワーオン時でSW2が押さない時、EEPROM内の0x9D03fff0番地内容が示す関数を実行。
// パワーオン時でSW2が押した時、EEPROM内の0x9D03fff4番地内容が示す関数を実行。
// W2が押した時の起動関数の処理を:202503 で追加
void power_on_start(){
if ((PORTB & 0x80) == 0) {// SW2が押されいる
unsigned *flag = (unsigned *) 0x9D03fff4;
if( *flag != 0xffffffff) {
void (* func)(void) = (void *) *flag;
func(); // EEPROM内の0x9D03fff4番地の関数を呼び出す
}
} else {// SW2が押されていない場合の起動
unsigned *flag = (unsigned *) 0x9D03fff0;
if( *flag != 0xffffffff) {
void (* func)(void) = (void *) *flag;
func(); // EEPROM内の0x9D03fff番地の関数を呼び出す
}
}
}
// :202503 で下記power_on_startを上記に変更
//void power_on_start(){
// if ((PORTB & 0x80) == 0) return; // SW2が押されてれば、リターン
// unsigned *flag = (unsigned *) 0x9D03fff0;
// if( *flag == 0xffffffff) return;
// void (* func)(void) = (void *) *flag;
// func(); // EEPROM内の0x9D03fff番地の関数を呼び出す
}
// 通常モードと、UARTコマンドモードを、My_APP_Tasks()関数内で切り替える関数 ;202504追加
int uart_command_mode = 1; // これが1の場合UARTコマンドモードで、0なら通常モード
int mode_change_request = 0;// これを1にすると、上記モードに切り替わって0に戻る
// 上記mode_change_requestを1にセットすると、uart_command_modeの設定に変更する。
// (_UME_THROUGH_MODE のスルーモードが1であれば、それが優先されます。)
int change_mode(){// 上記2つの変数に基づいて、モードを変更する
extern void recive_and_send_uart_with_polling();// my_uart.c
extern void uart_cmd_mode_polling();// my_uart.c
extern int core_once_count2_val;
if(mode_change_request == 0) return 0;// 切り替わらない
if(core_once_count2_val > 0) return 0;// 起動後の2秒間は実行しない。
mode_change_request = 0;//処理終了の変更
if( _HANDLES[_IDX_DEF_POLLS_UART] != (void *)recive_and_send_uart_with_polling
&& uart_command_mode == 0){ // 通常モードに変更
APP_State_Reset();
init_outBuffers(); //USB出力用リングバッファ関連変数 の初期化
_HANDLES[_IDX_DEF_POLLS_UART] = (void *)recive_and_send_uart_with_polling;
return 1;
}
if( _HANDLES[_IDX_DEF_POLLS_UART] != (void *)uart_cmd_mode_polling
&& uart_command_mode == 1){// UARTコマンドモードに強制変更
APP_State_Reset();
init_outBuffers(); //USB出力用リングバッファ関連変数 の初期化
_HANDLES[_IDX_DEF_POLLS_UART] = (void *)uart_cmd_mode_polling;
return 1;
}
return 0;
}
// 指定された int 変数を V に設定します。以下のコメントで示す変数を設定;202504追加
// specified_idがIDでなくポインタの場合は、その指し示す先のint変数を設定
void set_int_var(int specified_id, int value){
if(specified_id == _SPECIFIED_flagEcho){ // エコーモード変更用
extern int flagEcho;
flagEcho = value;
} else if(specified_id == _SPECIFIED_mode_change_request){
mode_change_request = value; // 通常モードとUARTコマンドの変更指示
} else if(specified_id == _SPECIFIED_uart_command_mode){
uart_command_mode = value; // 通常モードとUARTコマンドの変更指示
} else {
int *ptr = (int *)specified_id;
*ptr = value;// 識別子がポインタの場合は、そのポインタが示す変数を変更
}
}