swddude -- A SWD programmer for ARM Cortex microcontrollers.
Introducing swddude
But, many Cortex-M parts are small — 4x4 millimeters small — and don’t have the pins left over for JTAG.
For these parts, ARM introduced a new debug interface, called SWD.
Unfortunately, SWD isn’t well-supported by open-source tools.
Support is in progress in most of them — including my personal favorite,
OpenOCD — but I’ve had bad luck so far.
Anton Staaf was having the same issue, and decided to do something about it.
He tricked the cheap, commonly-available FTDI FT232H chip into speaking the line-level SWD protocol.
We’ve teamed up and, a week or so later, have something to show for it.
Presenting: swddude
, the dead-simple programmer for SWD microcontrollers.
(By “dead-simple” I mean “rather braindead” but it works!)
Currently it can flash code onto the LPC111x, LPC11Cxx, and LPC13xx series. Support for more chips is in progress.
I’ve posted a mirror of the code on GitHub for your cloning pleasure. Happy hacking!
swddude
swddude
is very young pre-alpha software.
Caveat downloader.
swddude
is a collection of simple tools for programming a
nd using ARM Cortex microcontrollers, such as the Cortex-M0 and M3, using the SWD protocol.
Why?
Larger ARM microcontrollers have JTAG interfaces.
OpenOCD and friends already do a great job flashing these micros.
But for smaller parts, such as the LPC11xx/LPC13xx series, ARM has defined a new low-pin-count debug interface called SWD.
OpenOCD doesn't yet support SWD.
In fact, when we started writing swddude
, no software on Mac or Linux could do what we wanted!
It's a shame not to be able to use these powerful little microcontrollers, so we wrote swddude
to scratch this itch.
What Can It Do?
Currently:
swddude
itself can flash code onto the NXP LPC11xx (Cortex-M0 based) and LPC13xx (Cortex-M3 based).swdprobe
can interrogate a SWD-compatible chip and dump information about what it finds.
This is useful when adding support for new chips toswddude
.swdhost
provides semihosting I/O for an attached microcontroller.
With semihosting, embedded software can sendprintf
-style messages
to a host computer through the debug connection -- no UART required.swddump
extracts the contents of Flash from a supported microcontroller.
We're working to extend the tools to support more microcontroller varieties.
Specifically, we're focusing on microcontrollers without JTAG ports --
devices that can't be easily added to OpenOCD (yet).
How Do I Use It?
You'll need a supported programmer and, of course, a supported microcontroller with a SWD interface.
Currently swddude
supports using the Bus Blaster (v2.5 programmed with the KT-link compatible CPLD configuration)
or any FTDI development board with an FT232H or FT2232H chip that has been wired to the SWD lines of your microcontroller.
Wire up your micro using the configuration described in swd_mpsse.h
.
Install libusb
1.0 and the libusb-compat
package.
The version supplied by your package manager (apt, Homebrew, etc.) should be fine.
Build a recent version of libftdi
.
As of this writing, you must build libftdi
from HEAD -- the released version (0.20)
still uses the legacy libusb
0.1 APIs and is incompatible with swddude
.
After checking out swddude
, build it like so:
$ cd swddude/source
$ make swddude release
This will deposit a swddude
binary in swddude/source/release
.
To program your microcontroller, you'll need to have your desired firmware in binary format
-- not ELF, and not Intel hex. Assuming it's in a file called firmware.bin
, you run:
$ swddude -flash firmware.bin -fix_lpc_checksum
This will default to the um232h programmer (FTDI's FT232H development board) configuration.
If you are using a Bus Blaster, you should add -programmer bus_blaster
to the command line above.
That last option, -fix_lpc_checksum
, adds the vector table checksum expected by the NXP LPC series.
Without it, your firmware won't run! If some other tool has already
written the correct checksum into your firmware, you can omit that option.
Status and Known Issues
These boards are known to work:
- LPCxpresso LPC1114.
- LPCxpresso LPC11C24.
- LPCxpresso LPC1343.
Note that the LPCxpresso boards will only work if you disable the proprietary LPC-Link programming device on the board.
On newer boards, you can do this by clearing solder jumpers between the two sections of the board;
older boards make you physically cut traces in the same position.
Known issues:
- Error reporting is not great. Most failures just print a stack trace,
which isn't helpful if you're not familiar with the source code.
In general, it's worth retrying at least once -- sometimes the SWD communications just need to be reset. swddude
makes no attempt at identifying the chip it's programming.
If you try programming an unsupported chip, it may do very bad things -- there is no safety net.- On the LPC1343 specifically, the SWD interfaces sometimes gets "stuck" and requires a power-cycle.
This will show up as failures very early during communication (often referencing the IDCODE register).
Brief Tour of the Source
The source code contains the following top-level directories:
build
: Anton Staaf's build system.libs
: Anton Staaf's support libraries, several of which we use.
(We currently include more than we strictly need here.)source
:swddude
and friends.
The source tree uses git's submodule feature aggressively.
If you check out swddude
using a simplegit clone
,
you'll be left with empty directories that won't build. You can fix this by running
git submodule update --recursive
Alternatively, you can make this happen automatically when you clone, like so:
git clone --recursive ${git_url}
//
// Copyright (c) 2013 SILICON LABORATORIES, INC.
//
// FILE NAME : dp_swd.c
// TARGET MCU : C8051F380
// DESCRIPTION : ARM CoreSight SW-DP Interface
//
// This file implements an interface to the ARM CoreSight Serial Wire Debug
// (SWD) - Debug Port (DP).
//
#include <compiler_defs.h>
#include "32bit_prog_defs.h" //-----------------------------------------------------------------------------
// Project Variables
//----------------------------------------------------------------------------- // Holds the last acknowledge error from the start of a move command.
// Also used by the Serial Wire module.
U8 idata ack_error; #if __C51__
// Note how the bit addresses are arranged to provide an endian swap.
// io_word is stored BE (matches the Keil C compliler), while the bit addresses
// are LE (matches the wire interface).
SEGMENT_VARIABLE (io_word, UU32, SEG_BDATA); // Used to provide bit addressable data for 8-bit and smaller shift routines.
// Also used by the Serial Wire module.
SEGMENT_VARIABLE (io_byte, U8, SEG_BDATA); SBIT (iow_0, io_word.U32, );
SBIT (iow_1, io_word.U32, );
SBIT (iow_2, io_word.U32, );
SBIT (iow_3, io_word.U32, );
SBIT (iow_4, io_word.U32, );
SBIT (iow_5, io_word.U32, );
SBIT (iow_6, io_word.U32, );
SBIT (iow_7, io_word.U32, ); SBIT (iow_8, io_word.U32, );
SBIT (iow_9, io_word.U32, );
SBIT (iow_10, io_word.U32, );
SBIT (iow_11, io_word.U32, );
SBIT (iow_12, io_word.U32, );
SBIT (iow_13, io_word.U32, );
SBIT (iow_14, io_word.U32, );
SBIT (iow_15, io_word.U32, ); SBIT (iow_16, io_word.U32, );
SBIT (iow_17, io_word.U32, );
SBIT (iow_18, io_word.U32, );
SBIT (iow_19, io_word.U32, );
SBIT (iow_20, io_word.U32, );
SBIT (iow_21, io_word.U32, );
SBIT (iow_22, io_word.U32, );
SBIT (iow_23, io_word.U32, ); SBIT (iow_24, io_word.U32, );
SBIT (iow_25, io_word.U32, );
SBIT (iow_26, io_word.U32, );
SBIT (iow_27, io_word.U32, );
SBIT (iow_28, io_word.U32, );
SBIT (iow_29, io_word.U32, );
SBIT (iow_30, io_word.U32, );
SBIT (iow_31, io_word.U32, ); SBIT (iob_0, io_byte, );
SBIT (iob_1, io_byte, );
SBIT (iob_2, io_byte, );
SBIT (iob_3, io_byte, );
SBIT (iob_4, io_byte, );
SBIT (iob_5, io_byte, );
SBIT (iob_6, io_byte, );
SBIT (iob_7, io_byte, );
#else
UU32 io_word;
volatile U8 bdata io_byte;
#endif //-----------------------------------------------------------------------------
// Variables Declarations
//----------------------------------------------------------------------------- // Controls SW connection sequence. 0=SW-DP, 1=SWJ-DP (use switch sequence)
U8 idata swj_dp_type; // Even parity lookup table, holds even parity result for a 4-bit value.
const U8 code even_parity[] =
{
0x00, 0x10, 0x10, 0x00,
0x10, 0x00, 0x00, 0x10,
0x10, 0x00, 0x00, 0x10,
0x00, 0x10, 0x10, 0x00
}; //-----------------------------------------------------------------------------
// SWD Host Command Handlers
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// StrobeSWCLK
//-----------------------------------------------------------------------------
//
// Pulls SWCLK high then low.
//
#define _StrobeSWCLK { SWCLK_Out = 1; SWCLK_Out = 0; } //-----------------------------------------------------------------------------
// SWD_Initialize
//-----------------------------------------------------------------------------
//
// Initializes SWD configuration data at startup.
//
void SWD_Initialize(void)
{
swj_dp_type = FALSE; // Default DP type is DP-SW
} //-----------------------------------------------------------------------------
// (0x20) SWD_Configure
//-----------------------------------------------------------------------------
//
// Sets the debug port (DP) type to either Serial Wire only or Serial Wire JTAG.
// The firmware needs to know this because the connection sequence is different
// depending on the DP type.
//
// Parameters:
// 1. DP_Type - Debug Port type. 0=SW, 1=SWJ
//
// Returns:
// 1. HOST_COMMAND_OK
//
STATUS SWD_Configure(U8 dp_type)
{
swj_dp_type = dp_type; return HOST_COMMAND_OK;
} //-----------------------------------------------------------------------------
// (0x21) SWD_Connect
//-----------------------------------------------------------------------------
//
// Sets the target device for Serial Wire communication and returns the
// 32-bit ID code. Must be called before performing any SWD commands.
//
// Returns:
// 1-4. IDCODE - Value read from the IDCODE register (32-bit).
// 5. Response code.
//
STATUS SWD_Connect(void)
{
U8 rtn; // Initialize IO pins for SWD interface
_SetSWPinsIdle; // Select the Serial Wire Debug Port
// Skip this switch sequence if the device does not have the swj_dp port
// Serial Wire + JTAG
SW_ShiftReset();
SW_ShiftByteOut(0x9E);
SW_ShiftByteOut(0xE7); // Reset the line and return the 32-bit ID code
rtn = SWD_LineReset();
//SendLongToHost(io_word.U32); return rtn;
} //-----------------------------------------------------------------------------
// (0x30) SWD_Disconnect
//-----------------------------------------------------------------------------
//
// Switches the debug interface to JTAG communication and disconnects pins.
//
// Returns:
// 1. HOST_COMMAND_OK
//
STATUS SWD_Disconnect(void)
{
// Initialize IO pins for SWD interface
_SetSWPinsIdle; // Select the JTAG Debug Port
// Skip this switch sequence if the device does not have the swj_dp port
// Serial Wire + JTAG
SW_ShiftReset();
SW_ShiftByteOut(0x3C);
SW_ShiftByteOut(0xE7); // Release debug interface pins except nSRST
_ResetDebugPins; return HOST_COMMAND_OK;
} //-----------------------------------------------------------------------------
// (0x31) SWD_LineReset
//-----------------------------------------------------------------------------
//
// Performs a line reset on the Serial Wire interface.
//
// Returns:
// 1. Response code.
//
STATUS SWD_LineReset(void)
{
U8 ack; // Complete SWD reset sequence (50 cycles high followed by 2 or more idle cycles)
SW_ShiftReset();
SW_ShiftByteOut(); // Now read the DPIDR register to move the SWD out of reset
ack = SW_ShiftPacket(SW_IDCODE_RD, );
SW_ShiftByteOut(); return SW_Response(ack);
} //-----------------------------------------------------------------------------
// (0x32) SWD_ClearErrors
//-----------------------------------------------------------------------------
//
// Clears all the error/sticky bits in the DP Control/Status register.
//
// Returns:
// 1-4. DP_CSR - DP_CTRLSTAT register value before the clear (32-bit, LE).
// 5-8. DP_CSR - DP_CTRLSTAT register value after the clear (32-bit, LE).
// 9. Response code.
//
STATUS SWD_ClearErrors(void)
{
U8 ack; // First read the DP-CSR register and send the value to the host.
SW_ShiftPacket(SW_CTRLSTAT_RD, );
//SendLongToHost(io_word.U32); // Clear all error/sticky bits by writing to the abort register.
io_word.U32 = 0x1E;
SW_ShiftPacket(SW_ABORT_WR, ); // Read the DP-CSR register again and send the results to the host.
ack = SW_ShiftPacket(SW_CTRLSTAT_RD, );
SW_ShiftByteOut();
//SendLongToHost(io_word.U32); return SW_Response(ack);
} //-----------------------------------------------------------------------------
// (0x34) SWD_DAP_Move
//-----------------------------------------------------------------------------
//
// Reads or writes one Debug/Access Port address one or more times.
//
// Parameters:
// 1. Count - Number of words to transfer minus one (i.e. 0=move 1 word).
// 2. DAP_Addr - The DAP register address to transfer one or more times.
// 3-n. Words[] - Array of 32-bit LE words (write transfers only).
//
// Returns:
// 1-n. Words[] - Array of 32-bit LE words (read transfers only).
// n+1. Response code.
//
// Uses:
// ack_error - Resets error accumulator.
//
STATUS SWD_DAP_Move(U8 cnt, U8 dap, U32 * transfer_data)
{
// Reset global error accumulator
ack_error = SW_ACK_OK; // Determine if this is a read or write transfer
if (dap & DAP_CMD_RnW)
{
// Perform the requested number of reads
SW_DAP_Read(cnt, dap, transfer_data);
}
else
{
SW_DAP_Write(cnt, dap, transfer_data, TRUE);
} // Finish with idle cycles
SW_ShiftByteOut(); // Return the accumulated error result
return SW_Response(ack_error);
} //-----------------------------------------------------------------------------
// SWD Helper Functions
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// SW_Response
//-----------------------------------------------------------------------------
//
// Converts SWD acknowledge value into a host response code.
//
// Parameters:
// SW_Ack - 3-bit SWD acknowledge code.
//
// Returns:
// 8-bit host response code.
//
STATUS SW_Response(U8 SW_Ack)
{
switch (SW_Ack)
{
case SW_ACK_OK: return HOST_COMMAND_OK;
case SW_ACK_WAIT: return HOST_AP_TIMEOUT;
case SW_ACK_FAULT: return HOST_ACK_FAULT;
default: return HOST_WIRE_ERROR;
}
} //-----------------------------------------------------------------------------
// SW_DAP_Read
//-----------------------------------------------------------------------------
//
// Does one or more reads of one Debug/Access Port register and returns each
// 32-bit word to the host.
//
// Parameters:
// cnt - Number of words to read minus one (i.e. 0=read 1 word).
// DAP_Addr - The DAP register address to read one or more times.
//
void SW_DAP_Read(U8 cnt, U8 DAP_Addr, U32 * read_data)
{
U8 req; // Format the packet request header
req = SW_Request(DAP_Addr); // Shift the first packet and if DP access, send the results
SW_ShiftPacket(req, );
if (!(req & SW_REQ_APnDP))
{
*read_data = io_word.U32;
read_data++;
} // Perform the requested number of reads
for (; cnt != ; cnt--)
{
SW_ShiftPacket(req, );
*read_data = io_word.U32;
read_data++;
} // For AP access, get and send results of the last read
if (req & SW_REQ_APnDP)
{
SW_ShiftPacket(SW_RDBUFF_RD, );
*read_data = io_word.U32;
read_data++;
}
} //-----------------------------------------------------------------------------
// SW_DAP_Write
//-----------------------------------------------------------------------------
//
// Does one or more writes to one Debug/Access Port register getting each
// 32-bit word from the host.
//
// Parameters:
// cnt - Number of words to write minus one (ie 0=write 1 word).
// DAP_Addr - The DAP register address to write one or more times.
// final - True if this is the final transfer of a move sequence.
//
void SW_DAP_Write(U8 cnt, U8 DAP_Addr, U32 * write_data, BOOL final)
{
U8 req; // Format the packet request header
req = SW_Request(DAP_Addr); // Perform the requested number of writes
do
{
io_word.U32 = *write_data;
write_data++;
#if 0
// Clear the upper half word for 16-bit packed writes
io_word.U16[MSB] = ; // For packed transfers, write 16-bits at a time
if (DAP_Addr & DAP_CMD_PACKED)
{
SW_ShiftPacket(req, );
io_word.U32 = *write_data;
write_data++; // Clear the upper half word for 16-bit packed writes
io_word.U16[MSB] = ;
}
else
{
io_word.U16[MSB] = (U16) *write_data;
write_data++;
}
#endif
SW_ShiftPacket(req, );
}
while (cnt-- != ); // For AP access, check results of last write (use default retry count
// because previous write may need time to complete)
if (final && (req & SW_REQ_APnDP))
{
SW_ShiftPacket(SW_RDBUFF_RD, );
}
} //-----------------------------------------------------------------------------
// SW_Request
//-----------------------------------------------------------------------------
//
// Converts DAP address into SWD packet request value.
//
// Parameters:
// DAP_Addr - 4-bit DAP address (A3:A2:RnW:APnDP).
//
// Returns:
// Complete 8-bit packet request value. Includes parity, start, etc.
//
U8 SW_Request(U8 DAP_Addr)
{
U8 req; // Convert the DAP address into a SWD packet request value
req = DAP_Addr & DAP_CMD_MASK; // mask off the bank select bits
req = req | even_parity[req]; // compute and add parity bit
req = req << ; // move address/parity bits
req = req | SW_REQ_PARK_START; // add start and park bits
return req;
} //-----------------------------------------------------------------------------
// SW_CalcDataParity
//-----------------------------------------------------------------------------
//
// Calculates even parity over the 32-bit value in io_word.U32. Contents of
// io_word are not changed.
//
// Returns:
// 1-bit even parity.
//
// Uses:
// io_word - Holds 32-bit value to compute parity on.
//
bit SW_CalcDataParity(void)
{
U8 parity; // Calculate column parity, reducing down to 4 columns
parity = io_word.U8[b0];
parity ^= io_word.U8[b1];
parity ^= io_word.U8[b2];
parity ^= io_word.U8[b3];
parity ^= parity >> ; // Use lookup table to get parity on 4 remaining bits. The cast (bit)
// converts any non-zero value to 1.
return (bit)even_parity[parity & 0xF];
} //-----------------------------------------------------------------------------
// SW_ShiftReset
//-----------------------------------------------------------------------------
//
// Puts the SWD into the reset state by clocking 64 times with SWDIO high.
// Leaves SWDIO an output and high.
//
void SW_ShiftReset(void)
{
U8 i; // Drive SWDIO high
SWDIO_Out = ;
_SetSWDIOasOutput; // Complete 64 SWCLK cycles
for (i = ; i != ; i--)
{
_StrobeSWCLK;
}
} //-----------------------------------------------------------------------------
// SW_ShiftPacket
//-----------------------------------------------------------------------------
//
// Completes one serial wire packet transfer (read or write). Expects SWDIO to
// be an output on entry.
//
// Parameters:
// request - Complete 8-bit packet request value. Includes parity, start, etc.
// retry - Number of times to try the request while the target ack is WAIT.
// 0 = use the system default retry count
// n = try the request upto n times
//
// Returns:
// 3-bit SWD acknowledge code.
// Leaves SWDIO an output and low.
//
// Uses:
// ack_error - Updated if there was a transfer error.
// io_byte - Used for all transfers.
// io_word - On entry, holds the 32-bit word data to transfer on writes.
// On exit, holds the 32-bit word data transfered on reads.
//
U8 SW_ShiftPacket(U8 request, U8 retry)
{
U8 ack, limit, i; // If retry parameter is zero, use the default value instead
if (retry == )
{
retry = DAP_RETRY_COUNT;
}
limit = retry; // While waiting, do request phase (8-bit request, turnaround, 3-bit ack)
do
{
// Turnaround or idle cycle, makes or keeps SWDIO an output
SWDIO_Out = ;
_SetSWDIOasOutput; // SWD = 0
_StrobeSWCLK; // SWC = 1, SWC = 0 -- IDLE State // Shift out the 8-bit packet request
SW_ShiftByteOut(request); // Turnaround cycle makes SWDIO an input
_SetSWDIOasInput; // Float, Pull Up
_StrobeSWCLK; // SWC = 1, SWC = 0 // Shift in the 3-bit acknowledge response
io_byte = ;
iob_0 = SWDIO_In; _StrobeSWCLK;
iob_1 = SWDIO_In; _StrobeSWCLK;
iob_2 = SWDIO_In; _StrobeSWCLK;
ack = io_byte; // Check if we need to retry the request
if ((ack == SW_ACK_WAIT) && --retry)
{
// Delay an increasing amount with each retry
for (i=retry; i < limit; i++);
}
else
{
break; // Request phase complete (or timeout)
}
}
while (TRUE); // If the request was accepted, do the data transfer phase (turnaround if
// writing, 32-bit data, and parity)
if (ack == SW_ACK_OK)
{
if (request & SW_REQ_RnW)
{
// Swap endian order while shifting in 32-bits of data
io_word.U8[b0] = SW_ShiftByteIn();
io_word.U8[b1] = SW_ShiftByteIn();
io_word.U8[b2] = SW_ShiftByteIn();
io_word.U8[b3] = SW_ShiftByteIn(); // Shift in the parity bit
iob_0 = SWDIO_In; _StrobeSWCLK; // Check for parity error
if (iob_0 ^ SW_CalcDataParity())
{
ack = SW_ACK_PARITY_ERR;
}
}
else
{
// Turnaround cycle makes SWDIO an output
_SetSWDIOasOutput; _StrobeSWCLK; // Swap endian order while shifting out 32-bits of data
SW_ShiftByteOut(io_word.U8[b0]);
SW_ShiftByteOut(io_word.U8[b1]);
SW_ShiftByteOut(io_word.U8[b2]);
SW_ShiftByteOut(io_word.U8[b3]); // Shift out the parity bit
SWDIO_Out = SW_CalcDataParity(); _StrobeSWCLK;
}
}
// TODO: Add error (FAULT, line, parity) handling here? RESEND on parity error? // Turnaround or idle cycle, always leave SWDIO an output
SWDIO_Out = ; _SetSWDIOasOutput; _StrobeSWCLK; // Update the global error accumulator if there was an error
if (ack != SW_ACK_OK)
{
ack_error = ack;
}
return ack;
} //-----------------------------------------------------------------------------
// SW_ShiftByteOut
//-----------------------------------------------------------------------------
//
// Shifts an 8-bit byte out the SWDIO pin.
//
// Parameters:
// byte - The 8-bit byte to shift out on SWDIO.
//
// Uses:
// io_byte - Holds byte as it is shifted out.
//
#pragma OT(8, SPEED)
void SW_ShiftByteOut(U8 byte)
{
// Make sure SWDIO is an output
_SetSWDIOasOutput; // Copy data to bit addressable location
io_byte = byte; // Shift 8-bits out on SWDIO
SWDIO_Out = iob_0; _StrobeSWCLK;
SWDIO_Out = iob_1; _StrobeSWCLK;
SWDIO_Out = iob_2; _StrobeSWCLK;
SWDIO_Out = iob_3; _StrobeSWCLK;
SWDIO_Out = iob_4; _StrobeSWCLK;
SWDIO_Out = iob_5; _StrobeSWCLK;
SWDIO_Out = iob_6; _StrobeSWCLK;
SWDIO_Out = iob_7; _StrobeSWCLK;
} //-----------------------------------------------------------------------------
// SW_ShiftByteIn
//-----------------------------------------------------------------------------
//
// Shifts an 8-bit byte in from the SWDIO pin.
//
// Returns:
// 8-bit byte value shifted in on SWDIO.
//
// Uses:
// io_byte - Holds byte as it is shifted in.
//
#pragma OT(8, SPEED)
U8 SW_ShiftByteIn(void)
{
// Make sure SWDIO is an input
_SetSWDIOasInput; // Shift 8-bits in on SWDIO
iob_0 = SWDIO_In; _StrobeSWCLK;
iob_1 = SWDIO_In; _StrobeSWCLK;
iob_2 = SWDIO_In; _StrobeSWCLK;
iob_3 = SWDIO_In; _StrobeSWCLK;
iob_4 = SWDIO_In; _StrobeSWCLK;
iob_5 = SWDIO_In; _StrobeSWCLK;
iob_6 = SWDIO_In; _StrobeSWCLK;
iob_7 = SWDIO_In; _StrobeSWCLK; // Return the byte that was shifted in
return io_byte;
}
swddude -- A SWD programmer for ARM Cortex microcontrollers.的更多相关文章
- Implementation of Serial Wire JTAG flash programming in ARM Cortex M3 Processors
Implementation of Serial Wire JTAG flash programming in ARM Cortex M3 Processors The goal of the pro ...
- 灵动微电子ARM Cortex M0 MM32F0010 UART1和UART2中断接收数据
灵动微电子ARM Cortex M0 MM32F0010 UART1和UART2中断接收数据 目录: 1.MM32F0010UART简介 2.MM32F0010UART特性 3.MM32F0010使用 ...
- 【ARM-Linux开发】ARM7 ARM9 ARM Cortex M3 M4 有什么区别
ARM7 ARM9 ARM Cortex M3 M4 区别 arm7 arm9 可以类比386和奔腾, 不同代,arm9相比arm7指令集和性能都有所增强,arm7和arm9都有带mmu和无mmu的版 ...
- 灵动微电子ARM Cortex M0 MM32F0010 Timer定时器中断定时功能的配置
灵动微电子ARM Cortex M0 MM32F0010 Timer定时器中断定时功能的配置 目录: 1.Timer1高级定时器Timer3通用定时器Timer14基本定时器简介 2.Timer1高级 ...
- 灵动微电子ARM Cortex M0 MM32F0010 GPIO 的配置驱动LED灯
灵动微电子ARM Cortex M0 MM32F0010 GPIO的配置 目录: 1.前言 2.学习方法简要说明 3.要点提示 4.注意事项 5.MM32F0010系统时钟的配置 6.MM32F001 ...
- ARM Cortex Design Considerations for Debug
JTAG was the traditional mechanism for debug connections for ARM7/9 parts, but with the Cortex-M fam ...
- ARM Cortex M3系列GPIO口介绍(工作方式探讨)
一.Cortex M3的GPIO口特性 在介绍GPIO口功能前,有必要先说明一下M3的结构框图,这样能够更好理解总线结构和GPIO所处的位置. Cortex M3结构框图 从图中可以看出 ...
- ARM Cortex M3(V7-M架构)硬件启动程序 二
解析 STM32 的启动过程 解析STM32的启动过程 当前的嵌入式应用程序开发过程里,并且C语言成为了绝大部分场合的最佳选择.如此一来main函数似乎成为了理所当然的起点——因为C程序往往从main ...
- ARM Cortex M3(V7-M架构)硬件启动程序 一
Cortex-m3启动代码分析笔记 启动代码文件名是STM32F10X.S,它的作用先总结下,然后再分析. 启动代码作用一般是: 1)堆和栈的初始化: 2)中断向量表定义: 3)地址重映射及中断向量表 ...
随机推荐
- MongoDB 之 "$" 的奇妙用法 MongoDB - 5
在MongoDB中有一个非常神奇的符号 "$" "$" 在 update 中 加上关键字 就 变成了 修改器 其实 "$" 字符 独立出现 ...
- (叉积)B - Toy Storage POJ - 2398
题目链接:https://cn.vjudge.net/contest/276358#problem/B 题目大意:和上一次写叉积的题目一样,就只是线不是按照顺序给的,是乱序的,然后输出的时候是按照有三 ...
- JS异常简单处理
有时候JS某一处报错会导致整个页面JS的运行出问题,于是想的简单研究一下JS的错误处理机制.更详细的可以自己参考网站研究: https://developer.mozilla.org/zh-CN/ ...
- 【坐在马桶上看算法】算法4:队列——解密QQ号
新学期开始了,小哈是小哼的新同桌(小哈是个小美女哦~),小哼向小哈询问QQ号,小哈当然不会直接告诉小哼啦,原因嘛你懂的.所以小哈给了小哼一串加密过的数字,同时小哈也告诉了小哼解密规则. ...
- Python学习系列之(一)---Python的安装
Python几乎可以在任何平台下运行,如我们所熟悉的:Windows/Unix/Linux/Macintosh. 在这里我们说一下,在Windows操作系统中安装python. 我的操作系统为:Win ...
- tensorflow中的kernel/Adam 变量的来源
原因是使用Adam优化函数时,Adam函数会创建一个Adam变量,目的是保存你使用tensorflow创建的graph中的每个可训练参数的动量, words/_word_embeddings:0 bi ...
- python日常
1.远程访问远程访问Jupyter Notebook,本地浏览器不能打开,先查了防火墙的状态,然后将设置的端口进行allow,网址,仍然拒绝链接,而后通过远程访问Jupyter Notebook,然后 ...
- C# 数据库数据动态插入(反射)
/// <summary> /// 提供将MySqlDataReader转成T类型的扩展方法 /// </summary> public static class MySqlD ...
- 在shell脚本中调用另一个脚本的三种不同方法(fork, exec, source)——转载
原文链接:http://blog.chinaunix.net/uid-22548820-id-3181798.html fork ( /directory/script.sh) :如果shell中包含 ...
- IntelliJ IDEA快捷键:Ctrl+空格
The Code Completion feature lets you quickly complete different kinds of statements in the code.For ...