#include "SWD_Module.h"
vu8 slowModeEnable = 0; // 默认不使能。0:不使能。1:使能!
vu8 AutoDownloadEnable = 0;
void SWD_Delay( void )
{
for( vu32 i=0;i<=3;i++ ); // 用于方便移植操作
}
/**
* @B 初始化SWD引脚和需要的功能!
*
*/
void SWDInit( void )
{
{ // IO引脚初始化
{ // 警告:使用了PB3/PB4,而这个是调试接口,默认是这个功能,所以需要去掉。
RCC->APB2ENR.AFIOClockEnable_RW = ENABLE; // 使能时钟
AFIO->MAPR.SerialWireJTAGConfiguration_W = 2; // 只启用SWD引脚!
}
if( HARDWARE_VERSION == LCD_VERSION )
{
RCC->APB2ENR.IOPBClockEnable_RW = ENABLE;
SWD_SWDIO_MODE_OUT; // 输出模式
SWD_SWDIO_PIN_OUT = 1; // 输出为1
GPIOB->CRL.InOutMode6_RW = GPIO_CR_INOUNTMODE_OUTPUT_50MHZ;
GPIOB->CRL.PinConfig6_RW = GPIO_CR_PINCONFG_OUT_GENERAL_PURPOSE_PUSHPULL; // RESET
SWD_RESET_PIN = 1; // 低电平复位,所以不复位
{ // SWCLK引脚控制:因为本身含有上拉电阻,所以使用开漏输出到1。
RCC->APB2ENR.IOPAClockEnable_RW = ENABLE;
GPIOA->CRH.InOutMode8_RW = GPIO_CR_INOUNTMODE_OUTPUT_50MHZ;
GPIOA->CRH.PinConfig8_RW = GPIO_CR_PINCONFG_OUT_GENERAL_PURPOSE_PUSHPULL; // 根据发现:使用开漏引脚,也会使输出0的能力降低,造成通信距离太短,出现dpID和错误和过程中容易出错!
SWD_SWCLK_PIN = 1; // 默认为高电平
GPIOA->CRL.InOutMode0_RW = GPIO_CR_INOUNTMODE_OUTPUT_50MHZ;
GPIOA->CRL.PinConfig0_RW = GPIO_CR_PINCONFG_OUT_GENERAL_PURPOSE_OPEN_DRAIN; // 引脚开漏输出
GPIOA->ODR.OutputData0_RW = 1;
GPIOA->CRL.InOutMode1_RW = GPIO_CR_INOUNTMODE_OUTPUT_50MHZ;
GPIOA->CRL.PinConfig1_RW = GPIO_CR_PINCONFG_OUT_GENERAL_PURPOSE_OPEN_DRAIN; // 引脚开漏输出
GPIOA->ODR.OutputData1_RW = 1;
}
}
else
{
RCC->APB2ENR.IOPAClockEnable_RW = ENABLE;
SWD_SWDIO_MODE_OUT; // 输出模式
SWD_SWDIO_PIN_OUT = 1; // 输出为1
GPIOB->CRL.InOutMode6_RW = GPIO_CR_INOUNTMODE_OUTPUT_50MHZ;
GPIOB->CRL.PinConfig6_RW = GPIO_CR_PINCONFG_OUT_GENERAL_PURPOSE_PUSHPULL; // RESET
SWD_RESET_PIN = 1; // 低电平复位,所以不复位
{ // 因为两个RESET引脚都用来复位,所以还需要PB1
GPIOB->CRL.InOutMode1_RW = GPIO_CR_INOUNTMODE_OUTPUT_50MHZ;
GPIOB->CRL.PinConfig1_RW = GPIO_CR_PINCONFG_OUT_GENERAL_PURPOSE_PUSHPULL; // RESET
GPIOB->ODR.OutputData1_RW = 1;
}
{ // SWCLK引脚控制:因为本身含有上拉电阻,所以使用开漏输出到1。
RCC->APB2ENR.IOPAClockEnable_RW = ENABLE;
GPIOA->CRL.InOutMode2_RW = GPIO_CR_INOUNTMODE_OUTPUT_50MHZ;
GPIOA->CRL.PinConfig2_RW = GPIO_CR_PINCONFG_OUT_GENERAL_PURPOSE_PUSHPULL; // 根据发现:使用开漏引脚,也会使输出0的能力降低,造成通信距离太短,出现dpID和错误和过程中容易出错!
SWD_SWCLK_PIN = 1; // 默认为高电平
}
}
}
}
void RAISE( u32 test )
{
GPIOC->ODR.OutputData8_RW = test&0x1; //
if( AutoDownloadEnable != ENABLE )
{
BeepCtrol(2,200);
}
}
/**
* @B 暂时的目标是要求稳定!所以其中的延时比较多!
* @Warning 在转换方向的时候,需要注意,因为自己加了缓冲器,方向需要注意!
* 结尾后:SWCLK保持为1
*/
void WRITE_BIT( u8 bit )
{
if( slowModeEnable == ENABLE )
{
SWD_Delay();
SWD_SWDIO_PIN_OUT = bit;
SWD_Delay();
SWD_SWCLK_PIN = 0;
SWD_Delay();
SWD_SWCLK_PIN = 1;
SWD_Delay();
}
else
{
SWD_SWDIO_PIN_OUT = bit;
SWD_SWCLK_PIN = 0;
SWD_SWCLK_PIN = 1;
}
}
u8 READ_BIT( void )
{
u8 bit;
if( slowModeEnable == ENABLE)
{
SWD_Delay( );
SWD_SWCLK_PIN = 0;
SWD_Delay( );
bit = SWD_SWDIO_PIN_IN;
SWD_Delay( );
SWD_SWCLK_PIN = 1;
SWD_Delay( );
}
else
{
SWD_SWCLK_PIN = 0;
bit = SWD_SWDIO_PIN_IN;
SWD_SWCLK_PIN = 1;
}
return bit;
}
/**
* @B 可以理解为TurnAround
*
*/
void SWCLK_CYCLE( void )
{
if( slowModeEnable == ENABLE)
{
SWD_Delay();
SWD_SWCLK_PIN = 0;
SWD_Delay();
SWD_SWCLK_PIN = 1;
SWD_Delay();
}
else
{
SWD_SWCLK_PIN = 0;
SWD_SWCLK_PIN = 1;
}
}
/**
* @B 可以理解为TurnAround
*
*/
void SWDIO_CYCLE( void )
{
if( slowModeEnable == ENABLE)
{
SWD_Delay();
SWD_SWDIO_PIN_OUT = 0;
SWD_Delay();
SWD_SWDIO_PIN_OUT = 1;
SWD_Delay();
}
else
{
SWD_SWDIO_PIN_OUT = 0;
SWD_SWDIO_PIN_OUT = 1;
}
}
/**
* @B 从AP或者DP寄存器里读出数据
* reg:显然只有4个(暂定的取值范围0-3)。 data为什么用指针,因为这样才能改变传递值,也就是指针指向的值
* 结尾后:SWCLK保持为1
*/
u32 readReg( u8 APnDPReg,u8 reg, u32 *data )
{
u8 i = 0;
u8 cb = 0; //
u8 parity; // 校验值
u8 b = 0; // 用于读ACK的位
u8 ack = 0; // ACK的值
u8 ret = SWD_ERROR_OK;
*data = 0;
int _APnDPReg = (int) APnDPReg;
int _read = (int) 1; // 读请求值为1
u8 A2 = reg & 0x01;
u8 A3 = ( reg>>1 ) & 0x01;
parity = ( _APnDPReg + _read + A2 + A3 ) & 0x01;
SWD_SWDIO_MODE_OUT; // 设置为输出模式
// SWD_SWDIO_DIR_CTR2 = BUFFER_IC_DIR_OUT; // 缓冲器设置为输出模式
{ // 启动发送序列
// 发送序列的问题:发送后,可以看出,其中SWCLK保持为1:
WRITE_BIT( 1 );
WRITE_BIT( _APnDPReg );
WRITE_BIT( _read );
WRITE_BIT( A2 );
WRITE_BIT( A3 );
WRITE_BIT( parity );
WRITE_BIT( 0 );
WRITE_BIT( 1 ); // SWDIO = 1, SWCLK = 0, SWCLK = 1
}
{ // TurnAround
{
SWD_SWDIO_MODE_IN; // 设置为输入模式
// SWD_SWDIO_DIR_CTR2 = BUFFER_IC_DIR_IN; // 缓冲器设置为输入模式
}
SWCLK_CYCLE();
}
{ // 读ACK
for( i=0;i<3;i++ )
{
b = READ_BIT( );
ack |= b< }
// 按照我的理解,这里不是应该有一个Trn的么?但是却没有
}
{ // 判断ACK位
if( ack == ACK_OK )
{
for( i=0;i<32;i++)
{
b = READ_BIT( );
*data |= b< if(b)
cb = !cb; // cb之前已经初始化了
}
parity = READ_BIT(); // 最后再读一下校验位
// 要使系统稳定的话,处理错误至关重要
if( cb == parity )
{
ret = SWD_ERROR_OK; // 系统正常
}
else
{
ret = SWD_ERROR_PARITY; // 校验错误,检验错误就可能是位操作不对,当然这个概率是50%
}
}
else if( ack == ACK_WAIT )
{
ret = SWD_ERROR_WAIT;
}
else if( ack == ACK_FAULT )
{
ret = SWD_ERROR_FAULT;
}
else
{
ret = SWD_ERROR_PROTOCOL; //协议出错,这个要注意了
}
}
{ // Turnaround
SWCLK_CYCLE();
}
{ // 进入8个Idle状态,确保传输
{
SWD_SWDIO_MODE_OUT; // 设置为输入模式
// SWD_SWDIO_DIR_CTR2 = BUFFER_IC_DIR_OUT; // 缓冲器设置为输入模式
}
for( i=0;i<8;i++ )
{
WRITE_BIT(0);
}
}
return ret; // 返回值
}
/**
* @B 这里有个要注意:可以忽视Ack,因为清除错误需要访问内容寄存器
*
*/
u32 writeReg( u8 APnDPReg,u8 reg,u32 data,u8 ignoreAck)
{
u8 ack = 0;
u8 i;
u8 parity = 0;
u8 b;
u8 ret = SWD_ERROR_OK;
u8 _APnDPReg = APnDPReg;
u8 _read = 0;
u8 A2 = reg&0x1;
u8 A3 = (reg>>1)&0x1;
parity = ( _APnDPReg + _read +A2 + A3 )&0x1; // 计算校验值
SWD_SWDIO_MODE_OUT; // 设置为输出模式
// SWD_SWDIO_DIR_CTR2 = BUFFER_IC_DIR_OUT; // 缓冲器设置为输出模式
{ // 启动发送序列
// 发送序列的问题:发送后,可以看出,其中SWCLK保持为1:
WRITE_BIT( 1 );
WRITE_BIT( _APnDPReg );
WRITE_BIT( _read );
WRITE_BIT( A2 );
WRITE_BIT( A3 );
WRITE_BIT( parity );
WRITE_BIT( 0 );
WRITE_BIT( 1 ); // SWDIO = 1, SWCLK = 0, SWCLK = 1 (这个由主机驱动为1的!手册说是不用主机驱动,但是由于上拉总线上会为1)
}
{
{ // 发现一个特别奇葩的问题:就是如果把这一句,放到SWCLK_CYCLE();之后就会出现:ACK错误,比较费解!
// 可能的原因:就是从机这个时候要驱动SWDIO,但是发现驱动不下来!!
// 最好的解决办法:就是通过读DP寄存器找到这个问题!
SWD_SWDIO_MODE_IN;
// SWD_SWDIO_DIR_CTR2 = BUFFER_IC_DIR_IN;
}
SWCLK_CYCLE();
}
{
{
// 读ACK
for( i=0;i<3;i++ )
{
b = READ_BIT( );
ack |= b< }
// 按照我的理解,这里不是应该有一个Trn的么?但是却没有,(最后发现读是没有的人,但是写是有的!写的在下面)
}
}
{ //
if( (ack == ACK_OK) || ignoreAck )
{
{ // 设置为输出
SWD_SWDIO_MODE_OUT; // 设置为输出模式
// SWD_SWDIO_DIR_CTR2 = BUFFER_IC_DIR_OUT; // 缓冲器设置为输出模式
}
SWCLK_CYCLE(); // 写的时候要用Trn一次。但是读的时候没有在代码里面看到。
parity = 0; // 这个函数有问题,当我改parity的时候,出现可以读状态,说明给器件的值存在检验错误!!这个是不应该的。这个要检查!
for( i=0;i<32;i++ )
{
b = ( data >> i)&0x1;
WRITE_BIT(b);
if(b)
parity = !parity;
}
WRITE_BIT(parity);
}
else if( ack == ACK_WAIT )
{
ret = SWD_ERROR_WAIT;
}
else if( ack == ACK_FAULT )
{
ret = SWD_ERROR_FAULT;
}
else
{
ret = SWD_ERROR_PROTOCOL; //协议出错,这个要注意了
}
{ // 进入8个Idle状态,确保传输,这个可以优化!
{ // 这个其实是多余的,一直是输出的,所以我都考虑这个源代码的性能了。
SWD_SWDIO_MODE_OUT; // 设置为输入模式
// SWD_SWDIO_DIR_CTR2 = BUFFER_IC_DIR_OUT; // 缓冲器设置为输入模式
}
for( i=0;i<8;i++ )
{
WRITE_BIT(0);
}
}
}
return ret;
}
/**
* @B 上电执行JTAG转SWD的序列函数!
*
*/
void JTAG_To_SWD_Sequence( void )
{
int i;
int b;
SWD_SWDIO_MODE_OUT; // 设置为输出模式
// SWD_SWDIO_DIR_CTR2 = BUFFER_IC_DIR_OUT; // 缓冲器设置为输出模式
{
SWD_SWDIO_PIN_OUT = 1; // 先输出为1
for( i=0;i<80;i++ )
{
SWCLK_CYCLE();
}
}
for( i=0;i<16;i++ )
{
b = ( JTAG_TO_SWD_VALUE>>i )&0x1;
WRITE_BIT(b);
}
{
SWD_SWDIO_PIN_OUT = 1;
for( i=0;i<60;i++ )
{
SWCLK_CYCLE();
}
}
{ // 执行16个空闲周期
SWD_SWDIO_PIN_OUT = 0;
for( i=0;i<16;i++ )
{
SWCLK_CYCLE();
}
SWD_SWDIO_PIN_OUT = 1; // 实际中,因为少了,这一句导致只能下载F1,F4/F2总是出现问题。
}
}
/**
* @B 写AP寄存器,在当前选择的APBANK。
*
*/
void writeAP( u8 reg,u32 data)
{
u8 forFault = 0;
forWait:
{
u8 swdStatus;
u8 retry = 1; // 这个是重试次数,但是日后应该做下载器,则这个变量是一定要提取出来的
do
{
swdStatus = writeReg(1,reg,data,FALSE);
retry--;
}while( (swdStatus == SWD_ERROR_WAIT) && retry>0 );
if( swdStatus != SWD_ERROR_OK )
{
if( swdStatus == SWD_ERROR_WAIT )
{
goto forWait; // 在测试F2的时候,出现了不定时的这个问题,所以才用这个方法!
}
else if( swdStatus == SWD_ERROR_FAULT )
{
if( forFault == 0 ) // 重试次数超出
{
forFault ++;
writeDP( DP_ABORT,0x1F);
goto forWait;
}
else
{
RAISE( swdStatus );
}
}
else
{
RAISE( swdStatus ); // 根据查询源码,这个函数的操作相对比较麻烦,需要自己日后重新定义!
}
}
}
}
/**
* @B 写DP寄存器
*
*/
void writeDP( u8 reg,u32 data )
{
u8 forFault = 0;
forWait:
{
u8 swdStatus;
u8 retry = 10; // 重试次数
do
{
swdStatus = writeReg(0,reg,data,FALSE);
retry--;
}while( (swdStatus == SWD_ERROR_WAIT) && retry>0 );
if( swdStatus != SWD_ERROR_OK )
{
if( swdStatus == SWD_ERROR_WAIT )
{
goto forWait; // 在测试F2的时候,出现了不定时的这个问题,所以才用这个方法!
}
else if( swdStatus == SWD_ERROR_FAULT )
{
if( forFault == 0 ) // 重试次数超出
{
forFault ++;
writeDP( DP_ABORT,0x1F);
goto forWait;
}
else
{
RAISE( swdStatus );
}
}
else
{
RAISE( swdStatus );
}
}
}
}
/**
* @B 写DP寄存器但是忽略ACK位,这个显然是出错之后的操作!
*
*/
void writeDPIgnoreAck( u8 reg,u32 data )
{
u8 forFault = 0;
forWait:
{
u8 swdStatus;
u8 retry = 10; // 重试次数
do
{
swdStatus = writeReg(0,reg,data,TRUE);
retry--;
}while( (swdStatus == SWD_ERROR_WAIT) && retry>0 );
if( swdStatus != SWD_ERROR_OK )
{
if( swdStatus == SWD_ERROR_WAIT)
{
goto forWait; // 在测试F2的时候,出现了不定时的这个问题,所以才用这个方法!
}
else if( swdStatus == SWD_ERROR_FAULT )
{
if( forFault == 0 ) // 重试次数超出
{
forFault ++;
writeDP( DP_ABORT,0x1F);
goto forWait;
}
else
{
RAISE( swdStatus );
}
}
else
{
RAISE( swdStatus ); // 出错处理特别重要!
}
}
}
}
/**
* @B 读AP
*
*/
void readAP( u8 reg,u32 *data )
{
u8 forFault = 0;
forWait:
{
u8 swdStatus;
u8 retry = 10; // 重试次数
do
{
swdStatus = readReg( 1,reg,data );
retry--;
}while( (swdStatus == SWD_ERROR_WAIT) && retry>0 );
if( swdStatus != SWD_ERROR_OK )
{
if( swdStatus == SWD_ERROR_WAIT)
{
goto forWait; // 在测试F2的时候,出现了不定时的这个问题,所以才用这个方法!
}
else if( swdStatus == SWD_ERROR_FAULT )
{
if( forFault == 0 ) // 重试次数超出
{
forFault ++;
writeDP( DP_ABORT,0x1F);
goto forWait;
}
else
{
RAISE( swdStatus );
}
}
else
{
RAISE( swdStatus ); // 出错处理特别重要!
}
}
}
}
/**
* @B 读DP
*
*/
void readDP( u8 reg,u32 * data )
{
u8 forFault = 0;
forWait:
{
u8 swdStatus;
u8 retry = 10; // 重试次数
do
{
swdStatus = readReg( 0,reg,data );
retry--;
}while( (swdStatus == SWD_ERROR_WAIT) && retry>0 );
if( swdStatus != SWD_ERROR_OK )
{
if( swdStatus == SWD_ERROR_WAIT)
{
goto forWait; // 在测试F2的时候,出现了不定时的这个问题,所以才用这个方法!
}
else if( swdStatus == SWD_ERROR_FAULT )
{
if( forFault == 0 ) // 重试次数超出
{
forFault ++;
writeDP( DP_ABORT,0x1F);
goto forWait;
}
else
{
RAISE( swdStatus );
}
}
else
{
RAISE( swdStatus ); // 出错处理特别重要!
}
}
}
}
/**
* @B 初始化DP,先发送一个转换序列,然后读出IDCode的值。
*
*/
u32 initDp( void )
{
u32 dpId;
JTAG_To_SWD_Sequence( );
readDP(DP_IDCODE,&dpId); //
//Debug power up request,这个应该是打开调试组件的电源,方便调试!
writeDP( DP_CTRL, DP_CTRL_CSYSPWRUPREQ | DP_CTRL_CDBGPWRUPREQ );
// Wait until we receive powerup ACK
int retry = 300;
u32 status;
while( retry>0 )
{
readDP(DP_CTRL,&status);
// 下面的这个是什么意思?
if ( ( status & ( DP_CTRL_CDBGPWRUPACK | DP_CTRL_CSYSPWRUPACK ) )
== ( DP_CTRL_CDBGPWRUPACK | DP_CTRL_CSYSPWRUPACK ) )
{
break;
}
retry--;
}
/* Throw error if we failed to power up the debug interface */
if ( ( status & ( DP_CTRL_CDBGPWRUPACK | DP_CTRL_CSYSPWRUPACK ) )
!= ( DP_CTRL_CDBGPWRUPACK | DP_CTRL_CSYSPWRUPACK ) )
{
// RAISE( SWD_ERROR_DEBUG_POWER ); // 这个出错不好管理!
RAISE( status );
}
/* Select first AP bank */
writeDP( DP_SELECT, 0x00 );
return dpId; // 应该是1BA01477(F4读出的值为:2BA01477) F2测试也是:2BA01477
}
/**
* @B 这个可能是针对EMF32单片机的,但是有一定的参考价值!这也能读出来东西,但是不知道是什么含义!
*/
u32 readApID( void )
{
u32 apId;
/* Select last AP bank */
writeDP( DP_SELECT, 0xf0 ); // 写DP寄存器中的APBBANKSEL位为0xF
// writeDP( DP_SELECT, 0x08000003 );
/* Dummy read AP ID */
readAP( AP_IDR, &apId );
/* Read AP ID */
readDP( DP_RDBUFF, &apId );
/* Select first AP bank again */
writeDP( DP_SELECT, 0x00 );
return apId; // EMF手册中说明这个值应该是:0x24770011(F4读出的值是这个!),但是实际读出来是0x14770011(F103)。不知道这是什么含义!
}
/**
* @B 不明觉厉
*
*/
/**********************************************************
* Sends the AAP Window Expansion Sequence. This sequence
* should be sent on SWDIO/SWCLK when reset is held low.
* This will cause the AAP window to be 255 times longer
* when reset is released.
**********************************************************/
void aapExtensionSequence( void )
{
int i;
SWD_RESET_PIN = 0;
SWD_SWCLK_PIN = 1;
for ( i = 0; i < 4; i++ )
{
SWDIO_CYCLE( );
}
SWD_SWCLK_PIN = 0;
for ( i = 0; i < 4; i++ )
{
SWDIO_CYCLE( );
}
SWD_SWCLK_PIN = 0;
SWD_RESET_PIN = 1;
}
/* 从下面开始,就是移植的另外一个程序--在SRAM中编程 ,具有不错的参考价值 */
/**
* @B 对于程序,务必要停止运行后,再写FLash操作!所以这个函数存在
*
*/
void connect_and_halt_core( void )
{
u32 rw_data;
rw_data = CHIPAP_BANK_F;
if( rw_data != 0x2430002 )
{
return;
}
}
/*以上,就是移植的另外一个程序--在SRAM中编程 ,具有不错的参考价值 */
/* 从下面开始,是自己的测试程序 */
u32 readMemoryFormStm32( void )
{
u32 apId = 0;
vu32 address = 0x08000000;
/* Select last AP bank */
// while(1)
{ // 按照下面的程序测试,速度大约是:4MHZ左右(3.7MHZ)测试一次!还是比较给力的。
writeDP( DP_SELECT, 0x00 ); // 访问寄存器
// writeDP( DP_SELECT, 0x08000003 );
writeAP( AP_CSW,0x2); // 长度为32bit
writeAP( AP_TAR,address); // 写目标地址
readAP( AP_DRW,&apId);
/* Read AP ID */
readDP( DP_RDBUFF, &apId );
address++;
}
return apId;
}
/**
* @B 测试
*
*/
void testFlashChearAndWrite( void )
{
{ // 清空Flash位
}
{ // 写Flash
}
}
#define CMX_AIRCR 0xE000ED0C
#define RUN_CMD_CRJ 0x05FA0007 // 这个是从:DAP中提取出来的,不知道行不行!!
#define CM3_DHCSR 0xE000EDF0
#define CM3_DEMCR 0xE000EDFC
/* Write these to DHCSR */
#define RUN_CMD 0xA05F0001
#define STOP_CMD 0xA05F0003
#define STEP_CMD 0xA05F0005
#define DEBUG_EVENT_TIMEOUT 200
/**
* @B Halting the MCU
*
*/
void haltTarget(void)
{
u32 tmp;
writeAP(AP_TAR, CM3_DEMCR);
readAP(AP_DRW, &tmp);
readDP(DP_RDBUFF, &tmp);
writeAP( AP_CSW,0x23000002); // 一定要先提前写上这个,不仅仅表示是32位,同时表明访问的方向是写访问!否则会报错!!
int timeout = DEBUG_EVENT_TIMEOUT;
writeAP(AP_TAR, CM3_DHCSR);
writeAP(AP_DRW, STOP_CMD);
writeAP(AP_TAR, CM3_DEMCR);
writeAP(AP_DRW, 0x01000401); // Write 1 to bit VC_CORERESET in DEMCR. This will enable halt-on-reset
uint32_t dhcrState;
do {
writeAP(AP_TAR, CM3_DHCSR);
readAP(AP_DRW, &dhcrState);
readDP(DP_RDBUFF, &dhcrState);
timeout--;
} while ( !(dhcrState & CoreDebug_DHCSR_S_HALT_Msk) && timeout > 0 );
if ( !(dhcrState & CoreDebug_DHCSR_S_HALT_Msk) ) {
// RAISE(dhcrState);
}
{ // 手册给的建议是:使能一个断点!!
}
}
/**
* @B 测试成功,可以启动程序!但是要注意CSW的值,需要设置为:0x23000002(暂时不明白含义,这个要注意!日后再做!)
*
*/
void runTarget(void)
{
uint32_t i;
writeAP( AP_CSW,0x23000002);
writeAP(AP_TAR, CM3_DEMCR);
writeAP(AP_DRW, 0x01000400); // 避免复位停在Reset!
for (i=0; i<100; i++);
writeAP(AP_TAR, CM3_DHCSR);
writeAP(AP_DRW, RUN_CMD);
for (i=0; i<100; i++);
writeAP(AP_TAR, CMX_AIRCR);
writeAP(AP_DRW, RUN_CMD_CRJ);
for (i=0; i<100; i++);
writeAP(AP_TAR, CMX_AIRCR);
writeAP(AP_DRW, RUN_CMD_CRJ);
}
/**********************************************************
* Reads one word from internal memory
*
* @param addr
* The address to read from
*
* @returns
* The value at @param addr
**********************************************************/
uint32_t readMem(uint32_t addr)
{
uint32_t ret;
writeAP(AP_TAR, addr);
readAP(AP_DRW, &ret);
readDP(DP_RDBUFF, &ret);
return ret;
}
/**********************************************************
* Writes one word to internal memory
*
* @param addr
* The address to write to
*
* @param data
* The value to write
*
* @returns
* The value at @param addr
**********************************************************/
void writeMem(uint32_t addr, uint32_t data)
{
writeAP(AP_TAR, addr);
writeAP(AP_DRW, data);
}
/**********************************************************
* Resets the target CPU by using the AIRCR register.
* The target will be halted immediately when coming
* out of reset. Does not reset the debug interface.
**********************************************************/
void resetAndHaltTarget(void)
{
uint32_t dhcsr;
int timeout = DEBUG_EVENT_TIMEOUT;
/* Halt target first. This is necessary before setting
* the VECTRESET bit */
haltTarget();
/* Set halt-on-reset bit */
writeMem(DEMCR, CoreDebug_DEMCR_VC_CORERESET_Msk);
/* Clear exception state and reset target */
writeAP(AP_TAR, AIRCR);
writeAP(AP_DRW, (0x05FA << SCB_AIRCR_VECTKEY_Pos) |
SCB_AIRCR_VECTCLRACTIVE_Msk |
SCB_AIRCR_VECTRESET_Msk);
/* Wait for target to reset */
do {
TimeDelayOfSoftAtMs(1);
timeout--;
dhcsr = readMem(DHCSR);
} while ( dhcsr & CoreDebug_DHCSR_S_RESET_ST_Msk );
/* Check if we timed out */
dhcsr = readMem(DHCSR);
if ( dhcsr & CoreDebug_DHCSR_S_RESET_ST_Msk )
{
// RAISE(SWD_ERROR_TIMEOUT_WAITING_RESET);
RAISE(1);
}
/* Verify that target is halted */
if ( !(dhcsr & CoreDebug_DHCSR_S_HALT_Msk) )
{
// RAISE(SWD_ERROR_TARGET_NOT_HALTED);
RAISE(1);
}
}
/**
* @B 清空STM32 Flash操作
*
*/
void clearAllFlash( void )
{
OS_ERR err;
writeAP( AP_CSW,0x23000002); // 一定要先提前写上这个,不仅仅表示是32位,同时表明访问的方向是写访问!否则会报错!!
writeAP(AP_TAR, (u32)&FLASH->KEYR.FlashProgramAndEraseControllerKey_W);
writeAP(AP_DRW, FLASH_KEY1);
writeAP(AP_TAR, (u32)&FLASH->KEYR.FlashProgramAndEraseControllerKey_W);
writeAP(AP_DRW, FLASH_KEY2);
{ // 清除错误
writeAP(AP_TAR, (u32)&FLASH->SR.All ) ;
writeAP(AP_DRW, _0b00110100);
}
writeAP( AP_CSW,0x00000002); // 读
u32 readWord0 = 0;
do
{
writeAP(AP_TAR, (u32)&FLASH->SR.All);
readAP(AP_DRW,&readWord0);
readDP(DP_RDBUFF,&readWord0);
}while(readWord0&0x1); // 当为1的时候说明没有操作完成!
writeAP( AP_CSW,0x23000002); // 一定要先提前写上这个,不仅仅表示是32位,同时表明访问的方向是写访问!否则会报错!!
writeAP( AP_TAR, (u32)&FLASH->CR.All );
writeAP( AP_DRW, _0b00000100 ); // 注意:擦除的时候要分开写。
writeAP( AP_TAR, (u32)&FLASH->CR.All );
writeAP( AP_DRW, _0b01000100 ); // 先写清除全片,再写开始位!!
writeAP( AP_CSW,0x00000002); // 读
u32 readWord1 = 0;
do
{
writeAP(AP_TAR, (u32)&FLASH->SR.All);
readAP(AP_DRW,&readWord1);
readDP(DP_RDBUFF,&readWord1);
}while(readWord1&0x1); // 当为1的时候说明没有操作完成!
{ // 根据客户反应,全片擦除有可能存在没有完成的地方,所以本次严格的按照操作来操作!!
//
do
{
writeAP(AP_TAR, (u32)&FLASH->SR.All);
readAP(AP_DRW,&readWord1);
readDP(DP_RDBUFF,&readWord1);
}while( ( readWord1&_0b00100000 ) != _0b00100000);
}
{ // 清除错误
writeAP( AP_CSW,0x23000002); // 一定要先提前写上这个,不仅仅表示是32位,同时表明访问的方向是写访问!否则会报错!!
writeAP(AP_TAR, (u32)&FLASH->SR.All);
writeAP(AP_DRW, _0b00110100);
}
OSTimeDlyHMSM(0,0,0,1000,OS_OPT_TIME_HMSM_NON_STRICT,&err);
}
/**
* @B 写Flash程序操作!测试!
*
*/
void writeFlash( void )
{
}
/**
* @B F0系列的保护操作选项,注意:F0系列的FLASH编程也是16bit一次编程这个和F1的操作是一样的。
@warning 实际中发现F0的寄存器分配和F1分配是一样的,所以选择用F1的寄存器进行操作。
*
*/
void stm32f0Protection( u8 readProtectionEnable,u8 writeProtectionEnable )
{
u32 readWord1 = 0;
// if( (readProtectionEnable == 1) || (writeProtectionEnable == 1 )) //
// {
{ // 解锁Flash操作
writeAP( AP_CSW,0x23000002); // 一定要先提前写上这个,不仅仅表示是32位,同时表明访问的方向是写访问!否则会报错!!
writeAP(AP_TAR, (u32)&FLASH->KEYR.FlashProgramAndEraseControllerKey_W);
writeAP(AP_DRW, FLASH_KEY1);
writeAP(AP_TAR, (u32)&FLASH->KEYR.FlashProgramAndEraseControllerKey_W);
writeAP(AP_DRW, FLASH_KEY2);
}
{
do
{
writeAP(AP_TAR, (u32)&FLASH->SR.All);
readAP(AP_DRW,&readWord1);
readDP(DP_RDBUFF,&readWord1);
}while(readWord1&0x1); // 当为1的时候说明没有操作完成!
}
{ // 解锁OptionsByte操作
writeAP(AP_TAR, (u32)&FLASH->OPTKEYR.OptionByteKey_W);
writeAP(AP_DRW, FLASH_KEY1);
writeAP(AP_TAR, (u32)&FLASH->OPTKEYR.OptionByteKey_W);
writeAP(AP_DRW, FLASH_KEY2);
}
{
writeAP(AP_TAR, (u32)&FLASH->CR.All);
writeAP(AP_DRW, _0b00100000 + 0x200 ); // 清除选项字节,注意:此时读保护依然在,写保护被清除,用户字节被清除
writeAP(AP_TAR, (u32)&FLASH->CR.All);
writeAP(AP_DRW, _0b01100000 + 0x200 ); // 开始操作
do
{
writeAP(AP_TAR, (u32)&FLASH->SR.All);
readAP(AP_DRW,&readWord1);
readDP(DP_RDBUFF,&readWord1);
}while(readWord1&0x1); // 忙时卡住
}
{ // 先不要置位读保护
}
{
writeAP(AP_TAR, (u32)&FLASH->CR.All);
writeAP(AP_DRW, _0b00000000 + 0x200 ); // 恢复现场
writeAP(AP_TAR, (u32)&FLASH->CR.All);
writeAP(AP_DRW, _0b00010000 + 0x200 ); // 选项字节编程使能!
}
{
if( readProtectionEnable == ENABLE ) // 默认状态下就是读保护使能的!(因为清除了!)
{
// writeAP(AP_TAR, (u32)&OB->RDP);
// writeAP(AP_DRW, 0x00); // 0x00也是读保护
}
else
{
writeAP( AP_CSW,0x23000001 ); // 长度为16bit,写(操作Flash必须用u16形式,否则会出问题!)
writeAP( AP_TAR, (u32)&OB->RDP );
if( ((u32)&OB->RDP)%4 != 0 )
{
writeAP( AP_DRW, 0xAA<<16 ); // 清除读保护,当值为0xAA时,关读保护!
}
else
{
writeAP( AP_DRW, 0xAA); // 清除读保护
}
}
if( writeProtectionEnable == ENABLE )
{
writeAP( AP_CSW,0x23000001 ); // 长度为16bit,写(操作Flash必须用u16形式,否则会出问题!)
writeAP( AP_TAR, (u32)&OB->WRP0 );
writeAP( AP_DRW, 0x00 );
writeAP( AP_TAR, (u32)&OB->WRP1 );
writeAP( AP_DRW, 0x00 );
writeAP( AP_TAR, (u32)&OB->WRP2 );
writeAP( AP_DRW, 0x00 );
writeAP( AP_TAR, (u32)&OB->WRP3 );
writeAP( AP_DRW, 0x00 );
}
else // 之前已经清除了,所以不需要管!
{
// writeAP(AP_TAR, (u32)&OB->RDP);
// writeAP(AP_DRW, 0xFFFFFFFF); // 清除读保护
}
writeAP( AP_CSW,0x23000002 ); // 恢复为32位
do
{
writeAP(AP_TAR, (u32)&FLASH->SR.All);
readAP(AP_DRW,&readWord1);
readDP(DP_RDBUFF,&readWord1);
}while(readWord1&0x1); // 忙时卡住
}
{
writeAP(AP_TAR, (u32)&FLASH->CR.All);
writeAP(AP_DRW, _0b00000000 + 0x200 ); // 恢复现场
writeAP(AP_TAR, (u32)&FLASH->CR.All);
writeAP(AP_DRW, _0b10000000); // 锁定操作
}
}