Keil使用技巧和常见问题

1 System Viewer中没有外设寄存器显示

1.1 现象

1.2 解决办法

需要指定SFR文件。
魔法棒 -> target -> 选择sfr文件。

2 no cortex-m sw device found

2.1 现象

在这里插入图片描述

1.确保接线正确;
2. 要使用正确的JLINK驱动版本
我是连接K3芯片的时候遇到的此问题。6.30的版本爆出此问题。安装新一些的版本(V7.86a)驱动就可以。

2.2 参考材料

[1] http://www.51hei.com/bbs/dpj-26907-1.html
[2] https://www.cnblogs.com/MyFlyLife/p/9068293.html
[3] https://blog.csdn.net/weixin_42108484/article/details/109724935

3 从FLM文件中提取flash算法

https://bbs.21ic.com/icview-2628494-1-1.html
https://bbs.21ic.com/icview-2630116-1-1.html
https://github.com/XIVN1987/MCUProg

3.1 code

#! python3
'''
 mbed
 Copyright (c) 2017-2017 ARM Limited
'''
import os
import io
import struct
import binascii
from collections import namedtuple

import jinja2
from elftools.elf.elffile import ELFFile


class PackFlashAlgo(object):
    REQUIRED_SYMBOLS = (
        'Init',
        'UnInit',
        'EraseSector',
        'ProgramPage',
    )

    EXTRA_SYMBOLS = (
        'BlankCheck',
        'EraseChip',
        'Verify',
        'Read',
    )

    def __init__(self, data):
        ''' 从ELF文件中依次解析出Flash信息和所需的symbols、sections,
            然后根据section的信息创建可在RAM中执行的算法程序的二进制blob '''
        self.elf = ElfFileSimple(data)

        self.flash_info = PackFlashInfo(self.elf)
        self.flash_start     = self.flash_info.start
        self.flash_size      = self.flash_info.size
        self.flash_page_size = self.flash_info.page_size


        self.symbols = {}
        for symbol in self.REQUIRED_SYMBOLS:
            if symbol not in self.elf.symbols: raise Exception('Missing symbol %s' % symbol)
            self.symbols[symbol] = self.elf.symbols[symbol].value
        for symbol in self.EXTRA_SYMBOLS:
            if symbol not in self.elf.symbols: self.symbols[symbol] = 0xFFFFFFFF
            else:                              self.symbols[symbol] = self.elf.symbols[symbol].value


        ''' 算法程序工程的link脚本:
        PRG 0 PI
        {
            PrgCode +0           ; Code
            {
                * (+RO)
            }
            
            PrgData +0           ; Data
            {
                * (+RW,+ZI)
            }
        }
        '''
        ro_rw_zi = [None, None, None]
        for section in self.elf.iter_sections():
            for i, name_and_type in enumerate((('PrgCode', 'SHT_PROGBITS'),
                                               ('PrgData', 'SHT_PROGBITS'),
                                               ('PrgData', 'SHT_NOBITS'),)):
                if name_and_type != (section.name, section['sh_type']): continue
                if ro_rw_zi[i] is not None: raise Exception('Duplicated section')

                ro_rw_zi[i] = section

        ''' 若zi段丢失,创建一个空的 '''
        s_ro, s_rw, s_zi = ro_rw_zi
        if s_rw is not None and s_zi is None:
            s_zi = {
                'sh_addr': s_rw['sh_addr'] + s_rw['sh_size'],
                'sh_size': 0
            }
        
        if s_ro is None: raise Exception('RO section is missing')
        if s_rw is None: raise Exception('RW section is missing')
        if s_zi is None: raise Exception('ZI section is missing')
        if s_ro['sh_addr'] != 0:
            raise Exception('RO section does not start at address 0')
        if s_ro['sh_addr'] + s_ro['sh_size'] != s_rw['sh_addr']:
            raise Exception('RW section does not follow RO section')
        if s_rw['sh_addr'] + s_rw['sh_size'] != s_zi['sh_addr']:
            raise Exception('ZI section does not follow RW section')

        self.ro_start = s_ro['sh_addr']
        self.ro_size  = s_ro['sh_size']
        self.rw_start = s_rw['sh_addr']
        self.rw_size  = s_rw['sh_size']
        self.zi_start = s_zi['sh_addr']
        self.zi_size  = s_zi['sh_size']

        
        algo_size = s_ro['sh_size'] + s_rw['sh_size'] + s_zi['sh_size']
        self.algo_data = bytearray(algo_size)
        for section in (s_ro, s_rw):
            start = section['sh_addr']
            size  = section['sh_size']
            assert len(section.data()) == size
            self.algo_data[start : start+size] = section.data()

    def format_algo_data(self, spaces, group_size, fmt):
        ''' 返回一个能表示algo_data的字符串 suitable for use in a template
            spaces: 每行的前导空格个数    group_size: 每行的元素个数    fmt: hex、c
        '''
        padding = ' ' * spaces
        if fmt == 'hex':
            blob = binascii.b2a_hex(self.algo_data)
            line_list = []
            for i in xrange(0, len(blob), group_size):
                line_list.append(''' + blob[i:i + group_size] + ''')
            return ('\n' + padding).join(line_list)
        elif fmt == 'c':
            blob = self.algo_data[:]
            pad_size = 0 if len(blob) % 4 == 0 else 4 - len(blob) % 4
            blob = blob + b'\x00' * pad_size
            integer_list = struct.unpack('<' + 'L' * (len(blob) // 4), blob)
            line_list = []
            for pos in range(0, len(integer_list), group_size):
                group = ['0x%08X' % value for value in
                         integer_list[pos:pos + group_size]]
                line_list.append(', '.join(group))
            return (',\n' + padding).join(line_list)
        else:
            raise Exception('Unsupported format %s' % fmt)

    def process_template(self, template_path, output_path, data_dict=None):
        ''' 用模板文件生成输出文件, 此类的所有数据都可以在模板中通过 'algo' 访问
            data_dict: 生成输出时模板需要的其他数据                        '''
        if data_dict is None: data_dict = {}
        
        assert 'algo' not in data_dict, 'algo already set by user data'
        data_dict['algo'] = self

        with open(template_path) as f:
            template = jinja2.Template(f.read())

            with open(output_path, 'wb') as f:
                f.write(template.render(data_dict).encode('latin'))


class PackFlashInfo(object):
    '''从ELF文件中解析出FlashDev.c文件中定义的FlashDevice结构体变量的值'''

    FLASH_DEVICE_STRUCT = '<H128sHLLLLBxxxLL'   # FlashDevice结构体的成员
    FLASH_SECTOR_STRUCT = '<LL'                 # FlashSector结构体的成员
    FLASH_DEVICE_STRUCT_SIZE = struct.calcsize(FLASH_DEVICE_STRUCT)
    FLASH_SECTOR_STRUCT_SIZE = struct.calcsize(FLASH_SECTOR_STRUCT)
    SECTOR_END = (0xFFFFFFFF, 0xFFFFFFFF)

    def __init__(self, elf):
        info = elf.symbols['FlashDevice']
        info_start = info.value
        info_size  = self.FLASH_DEVICE_STRUCT_SIZE
        info_data  = elf.read(info_start, info_size)

        values = struct.unpack(self.FLASH_DEVICE_STRUCT, info_data)

        self.version          = values[0]
        self.name             = values[1].strip(b'\x00')
        self.type             = values[2]
        self.start            = values[3]
        self.size             = values[4]
        self.page_size        = values[5]
        self.value_empty      = values[7]
        self.prog_timeout_ms  = values[8]
        self.erase_timeout_ms = values[9]

        self.sector_info_list = []
        for i in range(512):    # 最多512个sector
            data = elf.read(info_start + info_size + self.FLASH_SECTOR_STRUCT_SIZE * i, self.FLASH_SECTOR_STRUCT_SIZE)
            size, addr = struct.unpack(self.FLASH_SECTOR_STRUCT, data)

            if (size, addr) == self.SECTOR_END: break

            self.sector_info_list.append((addr, size))

    def __str__(self):
        desc = ''
        desc += 'Flash Device:' + os.linesep
        desc += '  name=%s'             % self.name             + os.linesep
        desc += '  version=0x%x'        % self.version          + os.linesep
        desc += '  type=%i'             % self.type             + os.linesep
        desc += '  start=0x%x'          % self.start            + os.linesep
        desc += '  size=0x%x'           % self.size             + os.linesep
        desc += '  page_size=0x%x'      % self.page_size        + os.linesep
        desc += '  value_empty=0x%x'    % self.value_empty      + os.linesep
        desc += '  prog_timeout_ms=%i'  % self.prog_timeout_ms  + os.linesep
        desc += '  erase_timeout_ms=%i' % self.erase_timeout_ms + os.linesep
        desc += '  sectors:' + os.linesep
        for sector_addr, sector_size in self.sector_info_list:
            desc += ('    addr=0x%x, size=0x%x' %(sector_addr, sector_size) + os.linesep)

        return desc


SymbolSimple = namedtuple('SymbolSimple', 'name, value, size')

class ElfFileSimple(ELFFile):
    ''' ELF对象包装,以更方便访问 symbols 和 rom '''

    def __init__(self, data):
        super(ElfFileSimple, self).__init__(io.BytesIO(data))

        self.symbols = {}   # 将 symbol table 中信息读出存入此中,方便访问
        for symbol in self.get_section_by_name('.symtab').iter_symbols():
            self.symbols[symbol.name] = SymbolSimple(symbol.name, symbol['st_value'], symbol['st_size'])

    def read(self, addr, size):     # 从ELF文件中读取程序数据        
        for segment in self.iter_segments():
            seg_addr = segment['p_paddr']
            seg_size = min(segment['p_memsz'], segment['p_filesz'])
            
            if addr >= seg_addr and addr + size <= seg_addr + seg_size:
                start = addr - seg_addr
                return segment.data()[start : start+size]
            else:
                continue


if __name__ == '__main__':
    # 中断halt程序,让函数执行完后返回到这里来执行从而让CPU自动halt住
    BLOB_HEADER = '0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2,'
    HEADER_SIZE = 0x20

    data_dict = {
        'name': 'STM32F10x_128',
        'prog_header': BLOB_HEADER,
        'header_size': HEADER_SIZE,
        'entry': 0x20000000,
        'stack_pointer': 0x20000000 + 2048,
    }
    
    for name in os.listdir(os.getcwd()):
        if os.path.isfile(name) and name.endswith('.FLM'):
            with open(name, 'rb') as f:
                algo = PackFlashAlgo(f.read())
                print(algo.flash_info)
                if 'algo' in data_dict: del data_dict['algo']
                algo.process_template('py_blob.tmpl', name.replace('.FLM', '.py'), data_dict)

代码模板文件

"""
 Flash OS Routines (Automagically Generated)
 Copyright (c) 2017-2017 ARM Limited
"""

flash_algo = {
    'load_address' : {{'0x%08X' %entry}},
    'instructions' : [
        {{prog_header}}
        {{algo.format_algo_data(8, 8, "c")}}
    ],

    'pc_Init'            : {{'0x%08X' %(entry + header_size + algo.symbols['Init'])}},
    'pc_UnInit'          : {{'0x%08X' %(entry + header_size + algo.symbols['UnInit'])}},
    'pc_EraseSector'     : {{'0x%08X' %(entry + header_size + algo.symbols['EraseSector'])}},
    'pc_ProgramPage'     : {{'0x%08X' %(entry + header_size + algo.symbols['ProgramPage'])}},
    'pc_Verify'          : {{'0x%08X' %(entry + header_size + algo.symbols['Verify'])}},
    'pc_EraseChip'       : {{'0x%08X' %(entry + header_size + algo.symbols['EraseChip'])}},
    'pc_BlankCheck'      : {{'0x%08X' %(entry + header_size + algo.symbols['BlankCheck'])}},
    'pc_Read'            : {{'0x%08X' %(entry + header_size + algo.symbols['Read'])}},
    
    'static_base'        : {{'0x%08X' %(entry + algo.rw_start + 0x20)}},
    'begin_data'         : {{'0x%08X' %(entry + algo.rw_start + 0x20 + algo.rw_size)}},
    'begin_stack'        : {{'0x%08X' %(entry + algo.rw_start + 0x20 + algo.rw_size + algo.flash_page_size + 1024)}},

    'analyzer_supported' : False,

    # Relative region addresses and sizes
    'ro_start'           : {{'0x%08X' %algo.ro_start}},
    'ro_size'            : {{'0x%08X' %algo.ro_size}},
    'rw_start'           : {{'0x%08X' %algo.rw_start}},
    'rw_size'            : {{'0x%08X' %algo.rw_size}},
    'zi_start'           : {{'0x%08X' %algo.zi_start}},
    'zi_size'            : {{'0x%08X' %algo.zi_size}},

    # Flash information
    'flash_start'        : {{'0x%08X' %algo.flash_start}},
    'flash_size'         : {{'0x%08X' %algo.flash_size}},
    'flash_page_size'    : {{'0x%08X' %algo.flash_page_size}},
    'sector_sizes': (
    {%- for start, size  in algo.flash_info.sector_info_list %}
        {{ "(0x%05X, 0x%05X)" % (start, size) }}, 
    {%- endfor %}
    )
}

4 RDDI-DAP Error

4.1 可能原因和解决办法

  1. 自己接杜邦线的问题。
    当仿真器与目标芯片之间的SWD线比较分散时(或者线比较长时),仿真器有时能正确识别到芯片的IDCODE,但是在擦除FLASH或者下载程序时就会出现“RDDI-DAP Error”问题。

【解决办法】
把SWD线约束成1股(建议)或者把SWD连接线尽可能缩短

【参考文献】
https://bbs.21ic.com/icview-3227066-1-1.html

  1. others
  • an unpowered target (check the target’s power supply)
  • a missing physical connection to the target (check your 10-pin Arm Cortex cable)
  • a maximum JTAG/SW clock that is set too high (lower the Max Clock frequency in the Target Driver Setup - Debug dialog)
  • a device in deep-sleep mode

【参考文献】
https://developer.arm.com/documentation/101636/0100/Appendix/Error-Messages

  1. 把SWD的频率调低
    https://blog.csdn.net/weixin_38253113/article/details/89843565

5 cannot load flash programming algorithm

【问题现象】
在这里插入图片描述

【问题原因】
Flash Download标签页里面 RAM for Algorithm中的size不对。 这样就会导致无法将算法下载到SRAM中去。
在这里插入图片描述

【参考文献】
https://community.st.com/t5/stm32-mcus-touchgfx-and-gui/cannot-load-flash-programming-algorithm-error/td-p/133981

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在开发过程中,printf函数是一种常用的输出日志信息的方式,可以帮助快速定位问题的原因。在单片机开发中,如果要使用printf函数,需要先对fputc函数进行重定向。这样,printf函数会先将用户字符串格式化,然后调用fputc函数逐个处理字符串中的字符,如果fputc函数被定义为串口输出函数,则printf最终会将字符串通过串口输出。这种方式是最常见的,但也可以通过适配不同的fputc函数来实现通过其他通信接口(比如SPI、CAN或屏幕)输出字符串。然而,从通信接口输出会比较耗时,不适用于一些实时性要求较高的系统。为了解决实时性问题,一些开发者发明了将fputc重定向输出到RAM,然后利用调试器从RAM中读取固定格式的数据来实现快速输出日志信息的方法。 在KEIL中,printf函数可以使用SEGGER的RTT组件来实现。RTT组件提供了SEGGER_RTT_printf函数,可以用于打印日志信息。这个函数需要指定要打印的字符串以及其他参数,在调用时会将格式化后的字符串通过fputc函数输出。然而,需要注意的是,SEGGER_RTT_printf函数不支持打印中文和浮点数。如果需要打印中文和浮点数,可以使用printf函数,并在fputc函数中调用该函数来实现。 另外,有人使用72MHz的stm32f105芯片配合KEIL的Event Recorder中间件进行打印测试,发现使用SEGGER的RTT组件的printf函数会比Event Recorder中间件的printf函数速度更快一些。这可能是因为Event Recorder中间件使用了printf函数,而SEGGER的RTT组件在精简了printf函数的基础上进行了优化,不支持浮点数和中文,从而提高了速度。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [调试笔记--keil printf小技巧](https://blog.csdn.net/weixin_42378319/article/details/117920784)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值