ARM MCU SWD离线调试器

#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<<i;

}

// 按照我的理解,这里不是应该有一个Trn的么?但是却没有

}

{ // 判断ACK位

if( ack == ACK_OK )

{

for( i=0;i<32;i++)

{

b = READ_BIT( );

*data |= b<<i;

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<<i;

}

// 按照我的理解,这里不是应该有一个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); // 锁定操作

}

}

相关推荐
编码追梦人2 分钟前
如何实现单片机的安全启动和安全固件更新
单片机
电子工程师UP学堂6 分钟前
电子应用设计方案-16:智能闹钟系统方案设计
单片机·嵌入式硬件
blessing。。2 小时前
I2C学习
linux·单片机·嵌入式硬件·嵌入式
嵌新程3 小时前
day03(单片机高级)RTOS
stm32·单片机·嵌入式硬件·freertos·rtos·u575
Lin2012303 小时前
STM32 Keil5 attribute 关键字的用法
stm32·单片机·嵌入式硬件
电工小王(全国可飞)4 小时前
STM32 RAM在Memory Map中被分为3个区域
stm32·单片机·嵌入式硬件
美式小田6 小时前
单片机学习笔记 9. 8×8LED点阵屏
笔记·单片机·嵌入式硬件·学习
兰_博7 小时前
51单片机-独立按键与数码管联动
单片机·嵌入式硬件·51单片机
时光の尘7 小时前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
嵌入式大圣9 小时前
单片机结合OpenCV
单片机·嵌入式硬件·opencv