Debug tools / show registers, memory and system clock data

Dependencies:   mbed CheckRTC

Target mbed board

LPC1768
LPC1114FN28
ST Nucleo L152RE
ST NUcleo F401RE
ST Nucleo F411RE

Command structure

Top

1 - goto step1 -> no connection all pins
2 - goto step2 -> connects pin_x and pin_y (not impliment yet)
t - Check and set RTC
x - Goto HW monitor
q - Return to main

>1

l - Check LED
b - Check button
s - CPU system info & clock
o - CPU clock output (Bug fix, port_mco1_mco2_set() function. Thanks Topi Makinen on April 25th, 2015)

>x(Hardware level monitor)

m - Entry Memory Mode
m>? -> Aditinal functions can see by ?
r - Entry Register Mode
r>? -> Aditinal functions can see by ?
s - System Clock -> sf, System / CPU information -> sc
q - Quit (back to called routine)
p - Entry Port Mode
p>? -> Aditinal functions can see by ?

Usage

Please modify "mon_hw_config.h" file for your purpose.
Especially LPC114FN28 has small memory, you cannot run your own program together with this program.
You don't need any additional HW. Just connect with PC via terminal software.

CAUTION

Due to several CPU's and short development time, I cannot grantee the quality level and several functions are not available yet.
If you found the bug, please let me know. Thanks in advance.

debug_tools/mon_hw_STM32.cpp

Committer:
kenjiArai
Date:
2015-04-26
Revision:
4:02980a730cfb
Parent:
3:455df34f7285

File content as of revision 4:02980a730cfb:

/*
 * mbed Application program for the ST NUCLEO Board
 * Monitor program Ver.3 for only for STM32F401RE,F411RE & STM32L152RE
 *
 *  Copyright (c) 2010-2015 Kenji Arai / JH1PJL
 *  http://www.page.sannet.ne.jp/kenjia/index.html
 *  http://mbed.org/users/kenjiArai/
 *      Started:  May        9th, 2010
 *      Created:  May       15th, 2010
 *          release as "monitor_01" http://mbed.org/users/kenjiArai/code/monitor_01/
 *      Spareted: June      25th, 2014      mon() & mon_hw()
 *      restart:  July      12th, 2014
 *      Revised:  April     25th, 2015      Bug fix ('o' command) pointed out by Topi Makinen
 *      Revised:  April     26th, 2015      Change Port output speed (set High speed)
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_L152RE)

//  Include ---------------------------------------------------------------------------------------
#include "mbed.h"
#include "mon_hw_config.h"
#include "mon_hw_common.h"
#include "mon_hw_STM32.h"

//  Object ----------------------------------------------------------------------------------------

//  Definition ------------------------------------------------------------------------------------
// USB Frequency
#define USB_FREQ_H          48100000
#define USB_FREQ_L          47900000

//  RAM -------------------------------------------------------------------------------------------
uint32_t SystemFrequency;
uint8_t quitflag;

uint32_t reg_save0, reg_save1, reg_save2, reg_save3, reg_save4, reg_save5, reg_save6;

//  ROM / Constant data ---------------------------------------------------------------------------
#if defined(TARGET_NUCLEO_F401RE)
char *const mon_msg =
    "HW monitor only for mbed Nucleo F401RE created on UTC:"__DATE__"("__TIME__")";

#if USE_MEM
const uint32_t mem_range[][2] = {   // Memory access range
    { 0x08000000, 0x0807ffff },     // On-chip Flash memory, 512KB Flash
    { 0x1fff0000, 0x1fff7a0f },     // System memory
    { 0x1fffc000, 0x1fffc007 },     // Option bytes
    { 0x20000000, 0x20017fff },     // Main Embedded SRAM, 96KB SRAM
    { 0x40000000, 0x5003ffff }      // IO area
};
#endif // USE_MEM
#elif defined(TARGET_NUCLEO_F411RE)
char *const mon_msg =
    "HW monitor only for mbed Nucleo F411RE created on UTC:"__DATE__"("__TIME__")";

#if USE_MEM
const uint32_t mem_range[][2] = {   // Memory access range
    { 0x08000000, 0x0807ffff },     // On-chip Flash memory, 512KB Flash
    { 0x1fff0000, 0x1fff7a0f },     // System memory
    { 0x1fffc000, 0x1fffc007 },     // Option bytes
    { 0x20000000, 0x2001ffff },     // Main Embedded SRAM, 128KB SRAM
    { 0x40000000, 0x5003ffff }      // IO area
};
#endif // USE_MEM
#elif defined(TARGET_NUCLEO_L152RE)
char *const mon_msg =
    "HW monitor only for mbed Nucleo L152RE created on UTC:"__DATE__"("__TIME__")";

#if USE_MEM
const uint32_t mem_range[][2] = {   // Memory access range
    { 0x08000000, 0x0807ffff },     // On-chip Flash memory, 512KB Flash
    { 0x08080000, 0x08083fff },     // EEPROM, 16KB
    { 0x1ff00000, 0x1ff01fff },     // System memory
    { 0x1ff80000, 0x1ff8009f },     // Option bytes
    { 0x20000000, 0x20013fff },     // Main Embedded SRAM, 32KB SRAM
    { 0x40000000, 0x400267ff }      // IO area
};
#endif // USE_MEM
#endif

char *const hmsg0 = "m  - Entry Memory Mode";
char *const hmsg1 = "m>? -> Aditinal functions can see by ?";
char *const hmsg2 = "r  - Entry Register Mode";
char *const hmsg3 = "r>? -> Aditinal functions can see by ?";
char *const hmsg4 = "s  - System Clock -> sf, System / CPU information -> sc";
char *const hmsg5 = "q  - Quit (back to called routine)";
char *const hmsg6 = "p  - Entry Port Mode";
char *const hmsg7 = "p>? -> Aditinal functions can see by ?";

char *const mrmsg0 = "Enter Register Mode u,i,s,t,a,d,l,w,c & ? for help";
#if (USE_UART==1) || (USE_SPI==1) || (USE_I2C == 1)
char *const mrmsg1 = "------";
char *const mrmsg2 = "USART";
//
char *const mrmsg4 = "I2C";
//
char *const mrmsg6 = "SPI";
//
#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
char *const mrmsg3 = "Enter u1,u2,u6 and u* for all";
char *const mrmsg5 = "Enter i1,i2,i3 and i* for all";
char *const mrmsg7 = "Enter s1,s2,s3,s4 and s* for all";
#elif defined(TARGET_NUCLEO_L152RE)
char *const mrmsg3 = "Enter u1,u2,u3,u5 and u* for all";
char *const mrmsg5 = "Enter i1,i2 and i* for all";
char *const mrmsg7 = "Enter s1,s2,s3 and s* for all";
#endif
#endif  // (USE_UART==1) || (USE_SPI==1) || (USE_I2C == 1)
char *const mrmsg8 = "Return to All Mode";

//-------------------------------------------------------------------------------------------------
//  Control Program
//-------------------------------------------------------------------------------------------------
// No function
static void not_yet_impliment( void )
{
    PRINTF("Not implimented yet");
    put_rn();
}

// No function
#if (USE_MEM==0)||(USE_PORT==0)||(USE_UART==0)||(USE_SPI==0)||(USE_I2C==0)||(USE_SYS==0)
static void not_select( void )
{
    PRINTF("Not select the function (refer mon_hw_config.h)");
    put_rn();
}
#endif

//  Help Massage
void hw_msg_hlp ( void )
{
    PRINTF(mon_msg);
    put_rn();
    PRINTF(hmsg0);
    put_rn();
    PRINTF(hmsg1);
    put_rn();
    PRINTF(hmsg6);
    put_rn();
    PRINTF(hmsg7);
    put_rn();
    PRINTF(hmsg2);
    put_rn();
    PRINTF(hmsg3);
    put_rn();
    PRINTF(hmsg4);
    put_rn();
    PRINTF(hmsg5);
    put_rn();
}

#if USE_MEM
#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
char *const rmsg0 = "FLASH    ";
char *const rmsg1 = "SYS-Mem  ";
char *const rmsg2 = "OPTION   ";
char *const rmsg3 = "SRAM     ";
char *const rmsg4 = "IO       ";
#elif defined(TARGET_NUCLEO_L152RE)
char *const rmsg0 = "FLASH    ";
char *const rmsg1 = "EEPROM   ";
char *const rmsg2 = "SYS-Mem  ";
char *const rmsg3 = "OPTION   ";
char *const rmsg4 = "SRAM     ";
char *const rmsg5 = "IO       ";
#endif

#include "mon_hw_mem.h"
#endif   // USE_MEM


//  Show 16bit register contents
void reg_print(uint16_t size, uint16_t reg)
{
    uint16_t i, j, k, n;

    i = j = k = n = 0;
    switch (size) {
        case SIZE8:
            PRINTF(rgmsg0);
            put_rn();
            i = 8;
            n = 0x80;
            break;
        case SIZE16:
            PRINTF("%s%s", rgmsg1, rgmsg0);
            put_rn();
            i = 16;
            n = 0x8000;
            break;
        case SIZE32:
            PRINTF("0x%08x", reg);
            return;
        default :
            ;
    }
    PUTC(' ');
    for (; i>0; i--) {
        k = n >> (size-i);
        j = reg & k;
        if (j) {
            PUTC('1');
        } else {
            PUTC('0');
        }
        PUTC(' ');
        PUTC(' ');
    }
    PRINTF("  (0x%04x)", reg);
}

#if USE_I2C
void i2c_reg( I2C_TypeDef* I2Cx )
{
    uint16_t reg;

    put_rn();
    reg = I2Cx->CR1;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg0 );
    PRINTF( imsg2 );
    put_rn();
    reg = I2Cx->CR2;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg1 );
    PRINTF( imsg2 );
    put_rn();
    reg = I2Cx->SR1;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg5 );
    PRINTF( imsg3 );
    put_rn();
    reg = I2Cx->SR2;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg6 );
    PRINTF( imsg3 );
    put_rn();
    reg = I2Cx->DR;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg2 );
    PRINTF( imsg4 );
    put_rn();
    reg = I2Cx->OAR1;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg7 );
    PRINTF( imsg6 );
    put_rn();
    reg = I2Cx->OAR2;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg8 );
    PRINTF( imsg6 );
    put_rn();
    reg = I2Cx->CCR;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg9 );
    PRINTF( imsg7 );
    put_rn();
    reg = I2Cx->TRISE;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg10 );
    PRINTF( imsg8 );
    put_rn();
}
#endif  // USE_I2C

#if USE_SPI
void spi_reg( SPI_TypeDef* SPIx )
{
    uint16_t reg;

    put_rn();
    reg = SPIx->CR1;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg0 );
    PRINTF( imsg2 );
    put_rn();
    reg = SPIx->CR2;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg1 );
    PRINTF( imsg2 );
    put_rn();
    reg = SPIx->SR;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg3 );
    PRINTF( imsg3 );
    put_rn();
    reg = SPIx->DR;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg2 );
    PRINTF( imsg4 );
    put_rn();
}
#endif  // USE_SPI

#if USE_UART
void usart_reg( USART_TypeDef* USARTx )
{
    uint16_t reg;

    put_rn();
    reg = USARTx->SR;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg3 );
    PRINTF( imsg3 );
    put_rn();
    reg = USARTx->DR;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg2 );
    PRINTF( imsg4 );
    put_rn();
    reg = USARTx->BRR;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg4 );
    PRINTF( imsg5 );
    put_rn();
    reg = USARTx->CR1;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg0 );
    PRINTF( imsg2 );
    put_rn();
    reg = USARTx->CR2;
    reg_print( SIZE32, reg );
    PRINTF( rnmsg1 );
    PRINTF( imsg2 );
    put_rn();
}
#endif  // USE_UART

#if USE_PORT
void rpt_port_one( GPIO_TypeDef* GPIOx )
{
    uint32_t i;

    PRINTF( " " );
    i = GPIOx->MODER;
    PRINTF( "0x%08x",i );
    i = GPIOx->OTYPER;
    PRINTF( " 0x%04x",i );
    i = GPIOx->OSPEEDR;
    PRINTF( "  0x%08x",i );
    i = GPIOx->PUPDR;
    PRINTF( " 0x%08x",i );
    i = GPIOx->IDR;
    PRINTF( " 0x%04x",i );
    i = GPIOx->ODR;
    PRINTF( " 0x%04x",i );
    put_rn();
}

void rpt_port( void )
{
    PRINTF( pnmsg0 );
    PRINTF( pnmsg1 );
    put_rn();
    PRINTF( pnmsga );
    rpt_port_one( GPIOA );
    PRINTF( pnmsgb );
    rpt_port_one( GPIOB );
    PRINTF( pnmsgc );
    rpt_port_one( GPIOC );
    PRINTF( pnmsgd );
    rpt_port_one( GPIOD );
    PRINTF( pnmsge );
    rpt_port_one( GPIOE );
    PRINTF( pnmsgh );
    rpt_port_one( GPIOH );
}

void port_inf_one( char *ptr )
{
    GPIO_TypeDef* GPIOx;
    uint32_t i,j;
    uint32_t pinpos;

    GPIOx = 0;
    PRINTF( pnmsg2 );
    switch ( *ptr ) {
        case 'a':
            GPIOx = GPIOA;
            PUTC( 'A' );
            break;
        case 'b':
            GPIOx = GPIOB;
            PUTC( 'B' );
            break;
        case 'c':
            GPIOx = GPIOC;
            PUTC( 'C' );
            break;
        case 'd':
            GPIOx = GPIOD;
            PUTC( 'D' );
            break;
        case 'e':
            GPIOx = GPIOE;
            PUTC( 'E' );
            break;
        case 'h':
            GPIOx = GPIOH;
            PUTC( 'H' );
            break;
    }
    i = GPIOx->MODER;
    put_rn();
    PRINTF( "-->Mode Reg.  (0x%08x)",i );
    put_rn();
    for ( pinpos = 0x00; pinpos < 16; pinpos++ ) {
        j = GPIO_MODER_MODER0 & (i >> (pinpos * 2));
        switch (j) {
            case GPIO_Mode_IN:
                PRINTF( "%2d= in", pinpos );
                break;
            case GPIO_Mode_OUT:
                PRINTF( "%2d=out", pinpos );
                break;
            case GPIO_Mode_AF:
                PRINTF( "%2d=alt", pinpos );
                break;
            case GPIO_Mode_AN:
                PRINTF( "%2d=ana", pinpos );
                break;
            default:
                break;
        }
        if ( (pinpos == 3) && (*ptr == 'h') ) {
            break;
        } else {
            if ( pinpos == 7 ) {
                put_rn();
            } else if ( pinpos == 15 ) {
                ;
            } else {
                PRINTF(", ");
            }
        }
    }
    i = GPIOx->OTYPER;
    put_rn();
    PRINTF( "%s type 1=push-pull, 0= open-drain", pnmsg4 );
    put_rn();
    reg_print( SIZE32,i);
    i = GPIOx->OSPEEDR;
    PRINTF( "%s speed [MHz] (0x%08x)", pnmsg4, i );
    put_rn();
    for ( pinpos = 0x00; pinpos < 16; pinpos++ ) {
        j = GPIO_OSPEEDER_OSPEEDR0 & (i >> (pinpos * 2));
        switch (j) {
            case GPIO_Speed_400KHz:
                PRINTF( "%2d=0.4", pinpos );
                break;
            case GPIO_Speed_2MHz:
                PRINTF( "%2d=  2", pinpos );
                break;
            case GPIO_Speed_10MHz:
                PRINTF( "%2d= 10", pinpos );
                break;
            case GPIO_Speed_40MHz:
                PRINTF( "%2d= 40", pinpos );
                break;
            default:
                break;
        }
        if ( (pinpos == 3) && (*ptr == 'h') ) {
            break;
        } else {
            if ( pinpos == 7 ) {
                put_rn();
            } else if ( pinpos == 15) {
                ;
            } else {
                PRINTF(", ");
            }
        }
    }
    i = GPIOx->PUPDR;
    put_rn();
    PRINTF( "-->Pullup(pup)/down(pdn) none(no)(0x%08x)",i );
    put_rn();
    for ( pinpos = 0x00; pinpos < 16; pinpos++ ) {
        j = GPIO_PUPDR_PUPDR0 & (i >> (pinpos * 2));
        switch (j) {
            case GPIO_PuPd_NOPULL:
                PRINTF( "%2d= no", pinpos );
                break;
            case GPIO_PuPd_UP:
                PRINTF( "%2d=pup", pinpos );
                break;
            case GPIO_PuPd_DOWN:
                PRINTF( "%2d=pdn", pinpos );
                break;
            default:
                break;
        }
        if ( (pinpos == 3) && (*ptr == 'h') ) {
            break;
        } else {
            if ( pinpos == 7 ) {
                put_rn();
            } else if ( pinpos == 15 ) {
                ;
            } else {
                PRINTF(", ");
            }
        }
    }
    put_rn();
    PRINTF( "%s %s", pnmsg5, pnmsg6);
    i = GPIOx->IDR;
    reg_print( SIZE32,i);
    put_rn();
    PRINTF( "%s %s", pnmsg4, pnmsg6);
    i = GPIOx->ODR;
    reg_print( SIZE32,i);
    put_rn();
}
#endif  // USE_PORT

#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
void port_mco1_mco2_set(uint8_t n)
{
    GPIO_TypeDef* GPIOx = 0;
    uint32_t temp = 0x00;

    if (n == 0){    // Just save the original setting
        // PA8 -> MCO_1
        GPIOx = GPIOA;
        reg_save0 = GPIOx->AFR[8 >> 3];
        reg_save1 = GPIOx->MODER;
        reg_save2 = GPIOx->OSPEEDR;
        GPIOx = GPIOC;
        reg_save3 = GPIOx->AFR[9 >> 3];
        reg_save4 = GPIOx->MODER;
        reg_save5 = GPIOx->OSPEEDR;
        reg_save6 = RCC->CFGR;
    } else {
        // PA8 -> MCO_1
        GPIOx = GPIOA;
        temp = ((uint32_t)(GPIO_AF0_MCO) << (((uint32_t)8 & (uint32_t)0x07) * 4)) ;
        GPIOx->AFR[8 >> 3] &= ~((uint32_t)0xf << ((uint32_t)(8 & (uint32_t)0x07) * 4)) ;
        GPIOx->AFR[8 >> 3] |= temp;
        GPIOx->MODER &= ~(GPIO_MODER_MODER0 << (8 * 2));
        GPIOx->MODER |= (0x2 << (8 * 2));
        GPIOx->OSPEEDR |= (0x03 << (8 * 2)); // High speed
        // PC9 -> MCO_2
        GPIOx = GPIOC;
        temp = ((uint32_t)(GPIO_AF0_MCO) << (((uint32_t)9 & (uint32_t)0x07) * 4)) ;
        GPIOx->AFR[9 >> 3] &= ~((uint32_t)0xf << ((uint32_t)(9 & (uint32_t)0x07) * 4)) ;
        GPIOx->AFR[9 >> 3] |= temp;
        GPIOx->MODER &= ~(GPIO_MODER_MODER0 << (9 * 2));
        GPIOx->MODER |= (0x2 << (9 * 2));
        GPIOx->OSPEEDR |= (0x03 << (9 * 2)); // High speed
        // Select output clock source
        RCC->CFGR &= 0x009fffff;
        if (n == 1){
            // MC0_1 output HSE 1/4, MCO_2 output SYSCLK 1/4
            //             MCO2          MCO2PRE       MCO1PRE       MCO1
            RCC->CFGR |= (0x0 << 30) + (0x6 << 27) + (0x6 << 24) + (0x3 << 22);
        } else {
            // MC0_1 output HSE 1/1, MCO_2 output SYSCLK 1/2
            //             MCO2          MCO2PRE       MCO1PRE       MCO1
            RCC->CFGR |= (0x0 << 30) + (0x4 << 27) + (0x0 << 24) + (0x3 << 22);
        }
    }
}

void port_mco1_mco2_recover(void)
{
    GPIO_TypeDef* GPIOx = 0;

    // PA8 -> MCO_1
    GPIOx = GPIOA;
    GPIOx->AFR[8 >> 3] = reg_save0;
    GPIOx->MODER = reg_save1;
    GPIOx->OSPEEDR = reg_save2;
    // PC9 -> MCO_2
    GPIOx = GPIOC;
    GPIOx->AFR[9 >> 3] = reg_save3;
    GPIOx->MODER = reg_save4;
    GPIOx->OSPEEDR = reg_save5;
    // MC0_1 & MCO_2
    RCC->CFGR = reg_save6;
}
#endif      // defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)

#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
void cpu_inf( char *ptr )
{
    uint32_t m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0;

    switch (*ptr++) {
        case 'f' :  // sc - show system clock frequency
            m1 = RCC->CR;
            PRINTF( "CR       = 0x%08x", m1 );
            put_rn();
            m1 = RCC->PLLCFGR;
            PRINTF( "PLLCFGR  = 0x%08x", m1 );
            put_rn();
            m1 = RCC->CFGR;
            PRINTF( "CFGR     = 0x%08x", m1 );
            put_rn();
            m1 = RCC->CIR;
            PRINTF( "CIR      = 0x%08x", m1 );
            put_rn();
            m1 = RCC->AHB1RSTR;
            PRINTF( "AHB1RSTR = 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB2RSTR;
            PRINTF( "APB2RSTR = 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB1RSTR;
            PRINTF( "APB1RSTR = 0x%08x", m1 );
            put_rn();
            m1 = RCC->AHB1ENR;
            PRINTF( "AHB1ENR  = 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB2ENR;
            PRINTF( "APB2ENR  = 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB2LPENR;
            PRINTF( "APB2LPENR= 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB1LPENR;
            PRINTF( "APB1LPENR= 0x%08x", m1 );
            put_rn();
            m1 = RCC->CSR;
            PRINTF( "CSR      = 0x%08x", m1 );
            put_rn();
            PRINTF(cmsg11);
            put_rn();
            m1 = PWR->CR;
            PRINTF( "CR       = 0x%08x", m1 );
            put_rn();
            m1 = PWR->CSR;
            PRINTF( "CSR      = 0x%08x", m1 );
            put_rn();
            put_rn();
        case 'F' :  // sF - show system clock frequency
            m1 = RCC->CFGR & RCC_CFGR_SWS;  /* Get SYSCLK source */
            switch (m1) {
                case 0x00:  // HSI used as system clock
                    PRINTF( "%s, %s%dHz", cmsg2, cmsg1,HSI_VALUE );
                    m2 = HSI_VALUE;
                    break;
                case 0x04:  // HSE used as system clock
                    PRINTF( "%s, %s%dHz", cmsg3, cmsg1, HSE_VALUE );
                    m2 = HSE_VALUE;
                    break;
                case 0x08:  // PLL used as system clock
                    PRINTF("fVCO = fPLL-in x (PLLN/PLLM), fPLL-out = fVCO/PLLP, fUSB-out = fVCO/PLLQ");
                    put_rn();
                    m5 = (RCC->PLLCFGR >> 6) & 0x1ff;   // PLLN
                    m1 = RCC->PLLCFGR & 0x3f;           // PLLM
                    PRINTF( "%s PLLN=%d, PLLM=%d", cmsg4, m5, m1 );
                    put_rn();
                    m3 = (RCC->PLLCFGR >> 22) & 0x1;    // Clock source
                    if (m3 == 0) {
                        // HSI oscillator clock selected as PLL clock source
                        m2 = (HSI_VALUE * (m5 / m1));
                        PRINTF( "%s, RC=%dHz", cmsg2, HSI_VALUE );
                    } else {
                        // HSE selected
                        m2 = (((HSE_VALUE) * m5) / m1);
                        if ((RCC->CR >> 18) & 0x01) {  // check HSEBYP bit
                            // HSE(not Xtal) selected as PLL clock source
                            PRINTF( "Use HSE(not Xtal but External Clock)=%dHz", HSE_VALUE );
                        } else {
                            // HSE(Xtal) selected as PLL clock source
                            PRINTF( "%s, Xtal=%dHz", cmsg3, HSE_VALUE );
                        }
                    }
                    put_rn();
                    PRINTF("PLL/Base   %s%dHz", cmsg1, m2);
                    put_rn();
                    m3 = (RCC->PLLCFGR >> 16) & 0x03;  // PLLP
                    switch (m3) {
                        case 0:
                            m3 = 2;
                            break;
                        case 1:
                            m3 = 4;
                            break;
                        case 2:
                            m3 = 6;
                            break;
                        case 3:
                            m3 = 8;
                            break;
                    }
                    m4 = (RCC->PLLCFGR >> 24) & 0x0f;  // PLLQ
                    PRINTF("%s PLLP=%d, PLLQ=%d", cmsg4, m3, m4);
                    put_rn();
                    PRINTF("PLL/System %s%dHz", cmsg1, m2/m3);
                    put_rn();
                    PRINTF("PLL/USB    %s%dHz", cmsg1, m2/m4);
                    m2 = m2/m4;
                    if ((m2 > USB_FREQ_H) || (m2 <USB_FREQ_L)) {
                        PRINTF(" -> USB Freq. is out of range!");
                    }
                    put_rn();
                    break;
                default:    // Not come here
                    PRINTF( cmsg5 );
                    break;
            }
            put_rn();
            PRINTF( "SYSCLK %s%dHz", cmsg6, HAL_RCC_GetSysClockFreq());
            put_rn();
            PRINTF( "HCLK   %s%dHz", cmsg6, HAL_RCC_GetHCLKFreq());
            put_rn();
            PRINTF( "PCLK1  %s%dHz", cmsg6, HAL_RCC_GetPCLK1Freq());
            put_rn();
            PRINTF( "PCLK2  %s%dHz", cmsg6, HAL_RCC_GetPCLK2Freq());
            put_rn();
            put_rn();
            // Check RTC Clock
            PRINTF("RTC Clock");
            put_rn();
            m1 = (RCC->BDCR >> 8) & 0x03;
            switch (m1) {
                case 0: // no clock
                    PRINTF(cmsg7);
                    break;
                case 1: // LSE
                    PRINTF(cmsg8);
                    break;
                case 2: // LSI
                    PRINTF("%s 17 to 47, typ.32KHz", cmsg9);
                    break;
                case 3: // HSE
                    PRINTF( cmsg10 );
                    m2 = (RCC->PLLCFGR >> 16) & 0x1f;   // RTCPRE
                    m3 = HSE_VALUE / m2;
                    PRINTF("%s%dHz", cmsg6, m3);
                    put_rn();
                    break;
                default:    // Not come here
                    PRINTF(cmsg5);
                    break;
            }
            put_rn();
            put_rn();
            break;
        case 'c' :      // sc - show system CPU information
            m1 = SCB->CPUID;
            m2 = ( m1 >> 24 );
            if ( m2 == 0x41 ) {
                PRINTF( "CPU = ARM " );
            } else {
                PRINTF( "CPU = NOT ARM " );
            }
            m2 = ( m1 >> 4 ) & 0xfff;
            if ( m2 == 0xc24 ) {
                PRINTF( "Cortex-M4" );
            } else {
                PRINTF( "NOT Cortex-M4" );
            }
            put_rn();
            m2 = ( m1 >> 20 ) & 0x0f;
            PRINTF( "Variant:%x", m2 );
            put_rn();
            m2 = m1 & 0x7;
            PRINTF( "Revision:%x", m2 );
            put_rn();
            PRINTF( "CPU ID: 0x%08x", m1 );
            put_rn();
            m1 = DBGMCU->IDCODE;
            PRINTF( "DBG ID: 0x%08x", m1 );
            put_rn();
            // unique ID
            // http://waijung.aimagin.com/index.htm?stm32f4_uidread.htm
            m1 = *(__IO uint32_t *)((uint32_t)0x1FFF7A10);
            PRINTF("Unique device ID(94bits):(1) 0x%08x ", m1);
            m1 = *(__IO uint32_t *)((uint32_t)0x1FFF7A14);
            PRINTF("(2) 0x%08x ", m1);
            m1 = *(__IO uint32_t *)((uint32_t)0x1FFF7A18);
            PRINTF( "(3) 0x%08x", m1 );
            put_rn();
            break;
        case '?' :
        default:
            PRINTF( "sc - System CPU information" );
            put_rn();
            PRINTF( "sf - System Clock" );
            put_rn();
    }
}
#elif defined(TARGET_NUCLEO_L152RE)

static __I uint8_t PLLMulTable[9] = {3, 4, 6, 8, 12, 16, 24, 32, 48};

void cpu_inf( char *ptr )
{
    uint32_t m1, m2, m3, m4, m5;

    switch (*ptr++) {
        case 'f' :  // sc - show system clock frequency
            m1 = RCC->CR;
            PRINTF( "CR       = 0x%08x", m1 );
            put_rn();
            m1 = RCC->ICSCR;
            PRINTF( "ICSCR    = 0x%08x", m1 );
            put_rn();
            m1 = RCC->CFGR;
            PRINTF( "CFGR     = 0x%08x", m1 );
            put_rn();
            m1 = RCC->CIR;
            PRINTF( "CIR      = 0x%08x", m1 );
            put_rn();
            m1 = RCC->AHBRSTR;
            PRINTF( "AHBRSTR  = 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB2RSTR;
            PRINTF( "APB2RSTR = 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB1RSTR;
            PRINTF( "APB1RSTR = 0x%08x", m1 );
            put_rn();
            m1 = RCC->AHBENR;
            PRINTF( "AHBENR   = 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB2ENR;
            PRINTF( "APB2ENR  = 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB2LPENR;
            PRINTF( "APB2LPENR= 0x%08x", m1 );
            put_rn();
            m1 = RCC->APB1LPENR;
            PRINTF( "APB1LPENR= 0x%08x", m1 );
            put_rn();
            m1 = RCC->CSR;
            PRINTF( "CSR      = 0x%08x", m1 );
            put_rn();
            PRINTF( cmsg11 );
            put_rn();
            m1 = PWR->CR;
            PRINTF( "CR       = 0x%08x", m1 );
            put_rn();
            m1 = PWR->CSR;
            PRINTF( "CSR      = 0x%08x", m1 );
            put_rn();
            put_rn();
        case 'F' :  // sF - show system clock frequency
            m1 = RCC->CFGR & RCC_CFGR_SWS;  /* Get SYSCLK source */
            switch (m1) {
                case 0x00:  // MSI used as system clock
                    m4 = ( RCC->ICSCR & RCC_ICSCR_MSIRANGE ) >> 13;
                    m2 = (32768 * (1 << (m4 + 1)));
                    PRINTF( "%s, %s%dHz", cmsg0, cmsg1, m2);
                    break;
                case 0x04:  // HSI used as system clock
                    PRINTF( "%s, %s%dHz", cmsg2, cmsg1,HSI_VALUE );
                    m2 = HSI_VALUE;
                    break;
                case 0x08:  // HSE used as system clock
                    PRINTF( "%s, %s%dHz", cmsg3, cmsg1, HSE_VALUE );
                    m2 = HSE_VALUE;
                    break;
                case 0x0C:  // PLL used as system clock
                    // Get PLL clock source and multiplication factor
                    m5 = RCC->CFGR & RCC_CFGR_PLLMUL;
                    m1 = RCC->CFGR & RCC_CFGR_PLLDIV;
                    m5 = PLLMulTable[(m5 >> 18)];
                    m1 = (m1 >> 22) + 1;
                    PRINTF( "%s Mul=%d, Div=%d", cmsg4, m5, m1 );
                    put_rn();
                    m3 = RCC->CFGR & RCC_CFGR_PLLSRC;
                    if ( m3 == 0x00 ) {
                        // HSI oscillator clock selected as PLL clock source
                        m2 = (((HSI_VALUE) * m5) / m1);
                        PRINTF( "%s, RC=%dHz", cmsg2, HSI_VALUE );
                    } else {
                        // HSE selected
                        m2 = (((HSE_VALUE) * m5) / m1);
                        if ((RCC->CR >> 18) & 0x01) {  // check HSEBYP bit
                            // HSE(not Xtal) selected as PLL clock source
                            PRINTF( "Use HSE(not Xtal but External Clock)=%dHz", HSE_VALUE );
                        } else {
                            // HSE(Xtal) selected as PLL clock source
                            PRINTF( "%s, Xtal=%dHz", cmsg3, HSE_VALUE );
                        }
                    }
                    put_rn();
                    PRINTF( "PLL %s%dHz", cmsg1, m2 );
                    put_rn();
                    break;
                default:    // Not come here
                    PRINTF( cmsg5 );
                    break;
            }
            put_rn();
            PRINTF( "SYSCLK %s%dHz", cmsg6, HAL_RCC_GetSysClockFreq() );
            put_rn();
            PRINTF( "HCLK   %s%dHz", cmsg6, HAL_RCC_GetHCLKFreq() );
            put_rn();
            PRINTF( "PCLK1  %s%dHz", cmsg6, HAL_RCC_GetPCLK1Freq() );
            put_rn();
            PRINTF( "PCLK2  %s%dHz", cmsg6, HAL_RCC_GetPCLK2Freq() );
            put_rn();
            put_rn();
            m1 = RCC->CSR & RCC_CSR_RTCSEL;
            // Check RTC & LCD Clock
            PRINTF("RTC/LCD Clock");
            put_rn();
            switch (m1) {
                case RCC_CSR_RTCSEL_NOCLOCK:
                    PRINTF( cmsg7 );
                    break;
                case RCC_CSR_RTCSEL_LSE:
                    PRINTF( cmsg8 );
                    break;
                case RCC_CSR_RTCSEL_LSI:
                    PRINTF("%s 26 to 56, typ.38KHz", cmsg9);
                    break;
                case RCC_CSR_RTCSEL_HSE:
                    PRINTF( cmsg10 );
                    break;
                default:    // Not come here
                    PRINTF( cmsg5 );
                    break;
            }
            put_rn();
            put_rn();
            break;
        case 'c' :      // sc - show system CPU information
            m1 = SCB->CPUID;
            m2 = ( m1 >> 24 );
            if ( m2 == 0x41 ) {
                PRINTF( "CPU = ARM " );
            } else {
                PRINTF( "CPU = NOT ARM " );
            }
            m2 = ( m1 >> 4 ) & 0xfff;
            if ( m2 == 0xc23 ) {
                PRINTF( "Cortex-M3" );
            } else {
                PRINTF( "NOT Cortex-M3" );
            }
            put_rn();
            m2 = ( m1 >> 20 ) & 0x0f;
            PRINTF( "Variant:%x", m2 );
            put_rn();
            m2 = m1 & 0x7;
            PRINTF( "Revision:%x", m2 );
            put_rn();
            PRINTF( "CPU ID: 0x%08x", m1 );
            put_rn();
            m1 = DBGMCU->IDCODE;
            PRINTF( "DBG ID: 0x%08x", m1 );
            put_rn();
            // unique ID
            // http://false.ekta.is/2013/09/stm32-unique-id-register-not-so-unique/
            m1 = *(__IO uint32_t *)((uint32_t)0x1FF80050);
            PRINTF("Unique device ID(94bits):(1) 0x%08x ", m1);
            m1 = *(__IO uint32_t *)((uint32_t)0x1FF80054);
            PRINTF("(2) 0x%08x ", m1);
            m1 = *(__IO uint32_t *)((uint32_t)0x1FF80058);
            PRINTF( "(3) 0x%08x", m1 );
            put_rn();
            break;
        case '?' :
        default:
            PRINTF( "sc - System CPU information" );
            put_rn();
            PRINTF( "sf - System Clock" );
            put_rn();
    }
}
#endif  // Select CPU

//-------------------------------------------------------------------------------------------------
//  Monitor Main Program
//-------------------------------------------------------------------------------------------------
int mon_hw(void)
{
    char *ptr;

    put_r();
    PRINTF("%s [Help:'?' key]", mon_msg);
    put_rn();
    for (;;) {
        put_r();
        PUTC('>');
        ptr = linebuf;
        get_line(ptr, buf_size);
        put_r();
        switch (*ptr++) {
                //-----------------------------------------------------------------------------------------
                //    Memory
                //-----------------------------------------------------------------------------------------
            case 'm' :
#if USE_MEM
                mem_inf(ptr);
                put_rn();
#else
                not_select();
#endif   // USE_MEM
                break;
                //-----------------------------------------------------------------------------------------
                //    Register
                //-----------------------------------------------------------------------------------------
            case 'r' :
                put_r();
                PRINTF(mrmsg0);
                put_rn();
                quitflag = 0;
                for (; quitflag != 0xff;) {
                    PRINTF("r>");
                    ptr = linebuf;
                    get_line(ptr, buf_size);
                    put_r();
                    switch(*ptr++) {
                        case 'u' :
#if USE_UART
                            switch(*ptr++) {
                                case '1' :
                                    PRINTF("%s%s1%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(USART1);
                                    break;
                                case '2' :
                                    PRINTF("%s%s2%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(USART2);
                                    break;
#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
                                case '6' :
                                    PRINTF("%s%s6%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(USART6);
                                    break;
#elif defined(TARGET_NUCLEO_L152RE)
                                case '3' :
                                    PRINTF("%s%s3%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(USART3);
                                    break;
                                case '5' :
                                    PRINTF("%s%s5%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(UART5);
                                    break;
#endif
                                case '*' :
                                    PRINTF( "%s & UART", mrmsg2 );
                                    put_rn();
                                    PRINTF("%s%s1%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(USART1);
                                    PRINTF("%s%s2%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(USART2);
#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
                                    PRINTF("%s%s6%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(USART6);
#elif defined(TARGET_NUCLEO_L152RE)
                                    PRINTF("%s%s3%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(USART3);
                                    PRINTF("%s%s5%s", mrmsg1,mrmsg2,mrmsg1);
                                    usart_reg(UART5);
#endif
                                    break;
                                case '?' :
                                default:
                                    PRINTF( mrmsg3 );
                                    put_rn();
                            }
#else
                            not_select();
#endif // USE_UART
                            break;
                        case 'i' :
#if USE_I2C
                            switch(*ptr++) {
                                case '1' :
                                    PRINTF("%s%s1%s", mrmsg1,mrmsg4,mrmsg1);
                                    i2c_reg( I2C1 );
                                    break;
                                case '2' :
                                    PRINTF("%s%s2%s", mrmsg1,mrmsg4,mrmsg1);;
                                    i2c_reg( I2C2 );
                                    break;
#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
                                case '3' :
                                    PRINTF("%s%s3%s", mrmsg1,mrmsg4,mrmsg1);;
                                    i2c_reg( I2C3 );
                                    break;
#endif
                                case '*' :
                                    PRINTF(mrmsg4);
                                    put_rn();
                                    PRINTF("%s%s1%s", mrmsg1,mrmsg4,mrmsg1);
                                    i2c_reg( I2C1 );
                                    PRINTF("%s%s2%s", mrmsg1,mrmsg4,mrmsg1);
                                    i2c_reg( I2C2 );
#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
                                    PRINTF("%s%s3%s", mrmsg1,mrmsg4,mrmsg1);;
                                    i2c_reg( I2C3 );
#endif
                                    break;
                                case '?' :
                                default:
                                    PRINTF(mrmsg5);
                                    put_rn();
                            }
#else
                            not_select();
#endif // USE_I2C
                            break;
                        case 's' :
#if USE_SPI
                            switch(*ptr++) {
                                case '1' :
                                    PRINTF("%s%s1%s", mrmsg1,mrmsg6,mrmsg1);
                                    spi_reg( SPI1 );
                                    break;
                                case '2' :
                                    PRINTF("%s%s2%s", mrmsg1,mrmsg6,mrmsg1);
                                    spi_reg( SPI2 );
                                    break;
                                case '3' :
                                    PRINTF("%s%s3%s", mrmsg1,mrmsg6,mrmsg1);
                                    spi_reg( SPI3 );
                                    break;
#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
                                case '4' :
                                    PRINTF("%s%s4%s", mrmsg1,mrmsg6,mrmsg1);
                                    spi_reg( SPI4 );
                                    break;
#endif
                                case '*' :
                                    PRINTF(mrmsg6);
                                    put_rn();
                                    PRINTF("%s%s1%s", mrmsg1,mrmsg6,mrmsg1);
                                    spi_reg( SPI1 );
                                    PRINTF("%s%s2%s", mrmsg1,mrmsg6,mrmsg1);
                                    spi_reg( SPI2 );
                                    PRINTF("%s%s3%s", mrmsg1,mrmsg6,mrmsg1);
                                    spi_reg( SPI3 );
#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
                                    PRINTF("%s%s4%s", mrmsg1,mrmsg6,mrmsg1);
                                    spi_reg( SPI4 );
#endif
                                    break;
                                case '?' :
                                default:
                                    PRINTF(mrmsg7);
                                    put_rn();
                            }
#else
                            not_select();
#endif // USE_SPI
                            break;
                        case 't' :      //
                            not_yet_impliment();
                            break;
                        case 'a' :      //
                            not_yet_impliment();
                            break;
                        case 'd' :      //
                            not_yet_impliment();
                            break;
                        case 'w' :      //
                            not_yet_impliment();
                            break;
                        case 'l' :        //
                            not_yet_impliment();
                            break;
                        case 'c' :      //
                            not_yet_impliment();
                            break;
                        case 'x' :      //
                            not_yet_impliment();
                            break;
                        case 'y' :      //
                            not_yet_impliment();
                            break;
                        case '?' :
                            PRINTF("u - USART");
                            put_rn();
                            PRINTF("i - I2C");
                            put_rn();
                            PRINTF("s - SPI");
                            put_rn();
                            PRINTF("t - TIMER");
                            put_rn();
                            PRINTF("a - ADC");
                            put_rn();
                            PRINTF("d - DAC");
                            put_rn();
                            PRINTF("l - LDC");
                            put_rn();
                            PRINTF("w - WWDG");
                            put_rn();
                            PRINTF("c - COMP");
                            put_rn();
                            break;
                        case 'q' :        // quit
                            quitflag = 0xff;
                            break;
                        default:
                            PUTC('?');
                            put_rn();
                    }
                }
                PRINTF(mrmsg8);
                put_rn();
                break;
                //-----------------------------------------------------------------------------------------
                //    Port
                //-----------------------------------------------------------------------------------------
            case 'p' :
#if USE_PORT
                put_r();
                PRINTF("Enter port a,b,c,d,e,h & * ? for help");
                put_rn();
                quitflag = 0;
                for (; quitflag != 0xff;) {
                    PRINTF("p>");
                    ptr = linebuf;
                    get_line(ptr, buf_size);
                    put_r();
                    switch(*ptr) {
                        case 'a' :
                        case 'b' :
                        case 'c' :
                        case 'd' :
                        case 'e' :
                        case 'h' :
                            port_inf_one(ptr);
                            break;
                        case '*' :
                            rpt_port();
                            break;
                        case '?' :
                            PRINTF("port a,b,c,d,e,h & *");
                            put_rn();
                            break;
                        case 'q' :        // quit
                            quitflag = 0xff;
                            break;
                        default:
                            PUTC('?');
                            put_rn();
                    }
                }
                PRINTF(mrmsg8);
                put_rn();
#else
                not_select();
#endif // USE_PORT
                break;
                //-----------------------------------------------------------------------------------------
                //    System
                //-----------------------------------------------------------------------------------------
            case 's' :    // System related information
#if USE_SYS
                cpu_inf(ptr);
#else
                not_select();
#endif   // USE_SYS
                break;
                //-----------------------------------------------------------------------------------------
                //    Help
                //-----------------------------------------------------------------------------------------
            case '?' :
                hw_msg_hlp();
                break;
                //-----------------------------------------------------------------------------------------
                //    Return to main routine
                //-----------------------------------------------------------------------------------------
            case 'q' :        // Quit
                put_r();
                PRINTF("Return to monitor");
                put_rn();
                return 0;
                //-----------------------------------------------------------------------------------------
                //    Special command for DEBUG
                //-----------------------------------------------------------------------------------------
            case 'x' :
                not_yet_impliment();
                break;
                //-----------------------------------------------------------------------------------------
                //    no support
                //-----------------------------------------------------------------------------------------
            default:
                PUTC('?');
                put_rn();
                break;
        }
    }
}
#endif  // defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_L152RE)