Introducing swddude

I love the ARM Cortex-M series of microcontrollers.
 
The sheer computational power they pack into a teensy, low-power package is almost embarrassing.

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 to swddude.
  • swdhost provides semihosting I/O for an attached microcontroller.
    With semihosting, embedded software can send printf-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.)
  • sourceswddude 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.的更多相关文章

  1. 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 ...

  2. 灵动微电子ARM Cortex M0 MM32F0010 UART1和UART2中断接收数据

    灵动微电子ARM Cortex M0 MM32F0010 UART1和UART2中断接收数据 目录: 1.MM32F0010UART简介 2.MM32F0010UART特性 3.MM32F0010使用 ...

  3. 【ARM-Linux开发】ARM7 ARM9 ARM Cortex M3 M4 有什么区别

    ARM7 ARM9 ARM Cortex M3 M4 区别 arm7 arm9 可以类比386和奔腾, 不同代,arm9相比arm7指令集和性能都有所增强,arm7和arm9都有带mmu和无mmu的版 ...

  4. 灵动微电子ARM Cortex M0 MM32F0010 Timer定时器中断定时功能的配置

    灵动微电子ARM Cortex M0 MM32F0010 Timer定时器中断定时功能的配置 目录: 1.Timer1高级定时器Timer3通用定时器Timer14基本定时器简介 2.Timer1高级 ...

  5. 灵动微电子ARM Cortex M0 MM32F0010 GPIO 的配置驱动LED灯

    灵动微电子ARM Cortex M0 MM32F0010 GPIO的配置 目录: 1.前言 2.学习方法简要说明 3.要点提示 4.注意事项 5.MM32F0010系统时钟的配置 6.MM32F001 ...

  6. ARM Cortex Design Considerations for Debug

    JTAG was the traditional mechanism for debug connections for ARM7/9 parts, but with the Cortex-M fam ...

  7. ARM Cortex M3系列GPIO口介绍(工作方式探讨)

    一.Cortex M3的GPIO口特性    在介绍GPIO口功能前,有必要先说明一下M3的结构框图,这样能够更好理解总线结构和GPIO所处的位置. Cortex M3结构框图     从图中可以看出 ...

  8. ARM Cortex M3(V7-M架构)硬件启动程序 二

    解析 STM32 的启动过程 解析STM32的启动过程 当前的嵌入式应用程序开发过程里,并且C语言成为了绝大部分场合的最佳选择.如此一来main函数似乎成为了理所当然的起点——因为C程序往往从main ...

  9. ARM Cortex M3(V7-M架构)硬件启动程序 一

    Cortex-m3启动代码分析笔记 启动代码文件名是STM32F10X.S,它的作用先总结下,然后再分析. 启动代码作用一般是: 1)堆和栈的初始化: 2)中断向量表定义: 3)地址重映射及中断向量表 ...

随机推荐

  1. waven 常用构建命令

    常用命令 mvn compile : 编译maven项目 mvn test : 运行项目测试用例 mvn package : 将项目打成jar包 mvn clean : 删除target目录下生成的文 ...

  2. CUDA性能优化----warp深度解析

    本文转自:http://blog.163.com/wujiaxing009@126/blog/static/71988399201701224540201/ 1.引言 CUDA性能优化----sp, ...

  3. 【源码阅读】Mimikatz一键获取远程终端凭据与获取明文密码修改方法

    1.前言 mimikatz框架是非常精妙的,粗浅讲一下修改的思路. 它的模块主要由各个结构体数组组成,根据传入的命令搜索执行相应命令的模块 mimikatz.c 部分代码: NTSTATUS mimi ...

  4. linux网桥浅析

    linux网桥浅析 原文链接:http://hi.baidu.com/_kouu/item/25787d38efec56637c034bd0 什么是桥接?简单来说,桥接就是把一台机器上的若干个网络接口 ...

  5. ecplise里的run as里只有run configurations是怎么回事?

    一.没有main方法 二.main方法所在的类不是在与文件名同名的类中

  6. Coursera台大机器学习技法课程笔记09-Decision Tree

    这是我们已经学到的(除Decision Tree外) 下面是一个典型的decision tree算法,有四个地方需要我们选择: 接着介绍了一个CART算法:通过decision stump分成两类,衡 ...

  7. On the Bias/Variance tradeoff in Machine Learning

    参考:https://codesachin.wordpress.com/2015/08/05/on-the-biasvariance-tradeoff-in-machine-learning/ 之前一 ...

  8. extjs6入门:用sencha cmd搭建简单的extjs6项目

    开发准备 1.sencha cmd安装 2.extjs6.0.0 gpl正式版下载,地址:https://www.sencha.com/legal/gpl/ ,解压ext-6.0.0-gpl.zip ...

  9. Servlet发送Http请求

    今日遇到一个需求,android注册,短信验证码功能. android请求我服务端,我请求tosms.cn发送验证码短信给android,于是需要在Servlet中发送Http请求 package o ...

  10. Smashing The Browser:From Vulnerability Discovery To Exploit学习记录

    浏览器Fuzz技术 漏洞挖掘 白盒挖掘 代码审计 自动化代码分析 黑盒挖掘 Fuzzing 两种Fuzzing技术 静态Fuzzing 基于变异的 文件.文档 多媒体 bf3 基于生成的 浏览器 重点 ...