parent
45db7ae1c4
commit
a8ae9496cb
@ -0,0 +1,87 @@
|
||||
|
||||
|
||||
#include "protob_helpers.h"
|
||||
|
||||
secbool send_protob_msg(uint8_t iface_num, uint16_t msg_id,
|
||||
const pb_msgdesc_t *fields, const void *msg,
|
||||
bool (*write)(pb_ostream_t *stream,
|
||||
const pb_byte_t *buf, size_t count),
|
||||
void (*write_flush)(write_state *state)) {
|
||||
// determine message size by serializing it into a dummy stream
|
||||
pb_ostream_t sizestream = {.callback = NULL,
|
||||
.state = NULL,
|
||||
.max_size = SIZE_MAX,
|
||||
.bytes_written = 0,
|
||||
.errmsg = NULL};
|
||||
if (false == pb_encode(&sizestream, fields, msg)) {
|
||||
return secfalse;
|
||||
}
|
||||
const uint32_t msg_size = sizestream.bytes_written;
|
||||
|
||||
write_state state = {
|
||||
.iface_num = iface_num,
|
||||
.packet_index = 0,
|
||||
.packet_pos = MSG_HEADER1_LEN,
|
||||
.buf =
|
||||
{
|
||||
'?',
|
||||
'#',
|
||||
'#',
|
||||
(msg_id >> 8) & 0xFF,
|
||||
msg_id & 0xFF,
|
||||
(msg_size >> 24) & 0xFF,
|
||||
(msg_size >> 16) & 0xFF,
|
||||
(msg_size >> 8) & 0xFF,
|
||||
msg_size & 0xFF,
|
||||
},
|
||||
};
|
||||
|
||||
pb_ostream_t stream = {.callback = write,
|
||||
.state = &state,
|
||||
.max_size = SIZE_MAX,
|
||||
.bytes_written = 0,
|
||||
.errmsg = NULL};
|
||||
|
||||
if (false == pb_encode(&stream, fields, msg)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
write_flush(&state);
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
secbool recv_protob_msg(uint8_t iface_num, uint32_t msg_size, uint8_t *buf,
|
||||
const pb_msgdesc_t *fields, void *msg,
|
||||
bool (*read)(pb_istream_t *stream, pb_byte_t *buf,
|
||||
size_t count),
|
||||
void (*read_flush)(read_state *state),
|
||||
uint16_t packet_size) {
|
||||
read_state state = {.iface_num = iface_num,
|
||||
.packet_index = 0,
|
||||
.packet_pos = MSG_HEADER1_LEN,
|
||||
.packet_size = packet_size,
|
||||
.buf = buf};
|
||||
|
||||
pb_istream_t stream = {.callback = read,
|
||||
.state = &state,
|
||||
.bytes_left = msg_size,
|
||||
.errmsg = NULL};
|
||||
|
||||
if (false == pb_decode_noinit(&stream, fields, msg)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
read_flush(&state);
|
||||
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id,
|
||||
uint32_t *msg_size) {
|
||||
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') {
|
||||
return secfalse;
|
||||
}
|
||||
*msg_id = (buf[3] << 8) + buf[4];
|
||||
*msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8];
|
||||
return sectrue;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "secbool.h"
|
||||
|
||||
#define USB_PACKET_SIZE 64
|
||||
#define MSG_HEADER1_LEN 9
|
||||
#define MSG_HEADER2_LEN 1
|
||||
|
||||
#define MSG_SEND_INIT(TYPE) TYPE msg_send = TYPE##_init_default
|
||||
#define MSG_SEND_ASSIGN_REQUIRED_VALUE(FIELD, VALUE) \
|
||||
{ msg_send.FIELD = VALUE; }
|
||||
#define MSG_SEND_ASSIGN_VALUE(FIELD, VALUE) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
msg_send.FIELD = VALUE; \
|
||||
}
|
||||
#define MSG_SEND_ASSIGN_STRING(FIELD, VALUE) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
memzero(msg_send.FIELD, sizeof(msg_send.FIELD)); \
|
||||
strncpy(msg_send.FIELD, VALUE, sizeof(msg_send.FIELD) - 1); \
|
||||
}
|
||||
#define MSG_SEND_ASSIGN_STRING_LEN(FIELD, VALUE, LEN) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
memzero(msg_send.FIELD, sizeof(msg_send.FIELD)); \
|
||||
strncpy(msg_send.FIELD, VALUE, MIN(LEN, sizeof(msg_send.FIELD) - 1)); \
|
||||
}
|
||||
#define MSG_SEND_ASSIGN_BYTES(FIELD, VALUE, LEN) \
|
||||
{ \
|
||||
msg_send.has_##FIELD = true; \
|
||||
memzero(msg_send.FIELD.bytes, sizeof(msg_send.FIELD.bytes)); \
|
||||
memcpy(msg_send.FIELD.bytes, VALUE, \
|
||||
MIN(LEN, sizeof(msg_send.FIELD.bytes))); \
|
||||
msg_send.FIELD.size = MIN(LEN, sizeof(msg_send.FIELD.bytes)); \
|
||||
}
|
||||
#define MSG_SEND_CALLBACK(FIELD, CALLBACK, ARGUMENT) \
|
||||
{ \
|
||||
msg_send.FIELD.funcs.encode = &CALLBACK; \
|
||||
msg_send.FIELD.arg = (void *)ARGUMENT; \
|
||||
}
|
||||
#define MSG_SEND(TYPE, WRITE, WRITE_FLUSH) \
|
||||
send_protob_msg(iface_num, MessageType_MessageType_##TYPE, TYPE##_fields, \
|
||||
&msg_send, WRITE, WRITE_FLUSH)
|
||||
|
||||
#define MSG_RECV_INIT(TYPE) TYPE msg_recv = TYPE##_init_default
|
||||
#define MSG_RECV_CALLBACK(FIELD, CALLBACK, ARGUMENT) \
|
||||
{ \
|
||||
msg_recv.FIELD.funcs.decode = &CALLBACK; \
|
||||
msg_recv.FIELD.arg = (void *)ARGUMENT; \
|
||||
}
|
||||
#define MSG_RECV(TYPE, READ, READ_FLUSH, PACKET_SIZE) \
|
||||
recv_protob_msg(iface_num, msg_size, buf, TYPE##_fields, &msg_recv, READ, \
|
||||
READ_FLUSH, PACKET_SIZE)
|
||||
|
||||
typedef struct {
|
||||
uint8_t iface_num;
|
||||
uint8_t packet_index;
|
||||
uint8_t packet_pos;
|
||||
uint8_t buf[USB_PACKET_SIZE];
|
||||
} write_state;
|
||||
|
||||
typedef struct {
|
||||
uint8_t iface_num;
|
||||
uint8_t packet_index;
|
||||
uint8_t packet_pos;
|
||||
uint16_t packet_size;
|
||||
uint8_t *buf;
|
||||
} read_state;
|
||||
|
||||
secbool send_protob_msg(uint8_t iface_num, uint16_t msg_id,
|
||||
const pb_msgdesc_t *fields, const void *msg,
|
||||
bool (*write_fnc)(pb_ostream_t *stream,
|
||||
const pb_byte_t *buf, size_t count),
|
||||
void (*write_flush)(write_state *state));
|
||||
|
||||
secbool recv_protob_msg(uint8_t iface_num, uint32_t msg_size, uint8_t *buf,
|
||||
const pb_msgdesc_t *fields, void *msg,
|
||||
bool (*read)(pb_istream_t *stream, pb_byte_t *buf,
|
||||
size_t count),
|
||||
void (*read_flush)(read_state *state),
|
||||
uint16_t packet_size);
|
||||
|
||||
secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id,
|
||||
uint32_t *msg_size);
|
@ -0,0 +1,9 @@
|
||||
use super::ffi;
|
||||
|
||||
pub fn ble_connected() -> bool {
|
||||
unsafe { ffi::ble_connected() }
|
||||
}
|
||||
|
||||
pub fn start_advertising(whitelist: bool) {
|
||||
unsafe { ffi::start_advertising(whitelist) }
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2014 - 2020 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. *
|
||||
* IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
;
|
||||
;----------------------------------------------------------------------
|
||||
;File : HardFaultHandler.S
|
||||
;Purpose : HardFault exception handler for IAR, Keil and GNU assembler.
|
||||
; Evaluates used stack (MSP, PSP) and passes appropiate stack
|
||||
; pointer to the HardFaultHandler "C"-routine.
|
||||
;------------- END-OF-HEADER ------------------------------------------
|
||||
;*/
|
||||
|
||||
#ifndef __IAR_SYSTEMS_ASM__
|
||||
#ifndef __CC_ARM
|
||||
#ifndef __clang__
|
||||
#ifndef __GNUC__
|
||||
#error "Unsupported assembler!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* Forward declarations of segments used
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
#if (defined(__IAR_SYSTEMS_ASM__))
|
||||
|
||||
SECTION CODE:CODE:NOROOT(2)
|
||||
SECTION CSTACK:DATA:NOROOT(3)
|
||||
|
||||
#elif (defined(__CC_ARM))
|
||||
|
||||
AREA OSKERNEL, CODE, READONLY, ALIGN=2
|
||||
PRESERVE8
|
||||
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* Publics
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
#if (defined(__IAR_SYSTEMS_ASM__))
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
PUBLIC HardFault_Handler
|
||||
|
||||
#elif (defined(__CC_ARM))
|
||||
|
||||
EXPORT HardFault_Handler
|
||||
|
||||
#elif (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, function
|
||||
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* Externals, code
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
#if (defined(__IAR_SYSTEMS_ASM__))
|
||||
|
||||
EXTERN HardFaultHandler
|
||||
|
||||
#elif (defined(__CC_ARM))
|
||||
|
||||
IMPORT HardFaultHandler
|
||||
|
||||
#elif (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
.extern HardFaultHandler
|
||||
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* CODE segment
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
#if (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
.syntax unified
|
||||
.thumb
|
||||
.balign 4
|
||||
.text
|
||||
|
||||
#else
|
||||
|
||||
THUMB
|
||||
|
||||
#endif
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* Global functions
|
||||
;*
|
||||
;**********************************************************************
|
||||
;*/
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* HardFault_Handler()
|
||||
;*
|
||||
;* Function description
|
||||
;* Evaluates the used stack (MSP, PSP) and passes the appropiate
|
||||
;* stack pointer to the HardFaultHandler "C"-routine.
|
||||
;*
|
||||
;* Notes
|
||||
;* (1) Ensure that HardFault_Handler is part of the exception table
|
||||
;*/
|
||||
#if (defined(__clang__) || defined(__GNUC__))
|
||||
HardFault_Handler:
|
||||
#else
|
||||
HardFault_Handler
|
||||
#endif
|
||||
#if (defined(__IAR_SYSTEMS_ASM__) && defined(__ARM6M__) && (__CORE__ == __ARM6M__)) || \
|
||||
(defined(__CC_ARM) && defined(__TARGET_ARCH_6S_M)) || \
|
||||
(defined(__clang__) && defined(__ARM_ARCH) && (__ARM_ARCH == 6)) || \
|
||||
(defined(__GNUC__) && (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__)))
|
||||
;// This version is for Cortex M0
|
||||
movs R0, #4
|
||||
mov R1, LR
|
||||
tst R0, R1 ;// Check EXC_RETURN in Link register bit 2.
|
||||
bne Uses_PSP
|
||||
mrs R0, MSP ;// Stacking was using MSP.
|
||||
b Pass_StackPtr
|
||||
#if (defined(__clang__) || defined(__GNUC__))
|
||||
Uses_PSP:
|
||||
#else
|
||||
Uses_PSP
|
||||
#endif
|
||||
mrs R0, PSP ;// Stacking was using PSP.
|
||||
#if (defined(__GNUC__) || defined(__clang__))
|
||||
Pass_StackPtr:
|
||||
#else
|
||||
Pass_StackPtr
|
||||
#endif
|
||||
#else
|
||||
;// This version is for Cortex M3, Cortex M4 and Cortex M4F
|
||||
tst LR, #4 ;// Check EXC_RETURN in Link register bit 2.
|
||||
ite EQ
|
||||
mrseq R0, MSP ;// Stacking was using MSP.
|
||||
mrsne R0, PSP ;// Stacking was using PSP.
|
||||
#endif
|
||||
#if (defined(__CC_ARM))
|
||||
ALIGN
|
||||
#endif
|
||||
ldr R1,=HardFaultHandler
|
||||
bx R1 ;// Stack pointer passed through R0.
|
||||
|
||||
#if (defined(__clang__) || defined(__GNUC__))
|
||||
.end
|
||||
#else
|
||||
END
|
||||
#endif
|
||||
|
||||
;/****** End Of File *************************************************/
|
@ -0,0 +1,155 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the monitor mode protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : JLINK_MONITOR.c
|
||||
Purpose : Implementation of debug monitor for J-Link monitor mode debug on Cortex-M devices.
|
||||
-------- END-OF-HEADER ---------------------------------------------
|
||||
*/
|
||||
|
||||
#include "JLINK_MONITOR.h"
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Configuration
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Types
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Static data
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Local functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Global functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* JLINK_MONITOR_OnExit()
|
||||
*
|
||||
* Function description
|
||||
* Called from DebugMon_Handler(), once per debug exit.
|
||||
* May perform some target specific operations to be done on debug mode exit.
|
||||
*
|
||||
* Notes
|
||||
* (1) Must not keep the CPU busy for more than 100 ms
|
||||
*/
|
||||
void JLINK_MONITOR_OnExit(void) {
|
||||
//
|
||||
// Add custom code here
|
||||
//
|
||||
// BSP_ClrLED(0);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* JLINK_MONITOR_OnEnter()
|
||||
*
|
||||
* Function description
|
||||
* Called from DebugMon_Handler(), once per debug entry.
|
||||
* May perform some target specific operations to be done on debug mode entry
|
||||
*
|
||||
* Notes
|
||||
* (1) Must not keep the CPU busy for more than 100 ms
|
||||
*/
|
||||
void JLINK_MONITOR_OnEnter(void) {
|
||||
//
|
||||
// Add custom code here
|
||||
//
|
||||
// BSP_SetLED(0);
|
||||
// BSP_ClrLED(1);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* JLINK_MONITOR_OnPoll()
|
||||
*
|
||||
* Function description
|
||||
* Called periodically from DebugMon_Handler(), to perform some actions that need to be performed periodically during debug mode.
|
||||
*
|
||||
* Notes
|
||||
* (1) Must not keep the CPU busy for more than 100 ms
|
||||
*/
|
||||
void JLINK_MONITOR_OnPoll(void) {
|
||||
//
|
||||
// Add custom code here
|
||||
//
|
||||
// BSP_ToggleLED(0);
|
||||
// _Delay(500000);
|
||||
}
|
||||
|
||||
/****** End Of File *************************************************/
|
@ -0,0 +1,65 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the monitor mode protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : JLINK_MONITOR.h
|
||||
Purpose : Header file of debug monitor for J-Link monitor mode debug on Cortex-M devices.
|
||||
-------- END-OF-HEADER ---------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef JLINK_MONITOR_H
|
||||
#define JLINK_MONITOR_H
|
||||
|
||||
void JLINK_MONITOR_OnExit (void);
|
||||
void JLINK_MONITOR_OnEnter (void);
|
||||
void JLINK_MONITOR_OnPoll (void);
|
||||
|
||||
#endif
|
||||
|
||||
/****** End Of File *************************************************/
|
@ -0,0 +1,927 @@
|
||||
/*********************************************************************
|
||||
* (c) SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
* www.segger.com *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 1995 - 2020 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the monitor mode protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : JLINK_MONITOR_ISR_SES.s
|
||||
Purpose : Implementation of debug monitor for J-Link monitor mode
|
||||
debug on Cortex-M devices, supporting SES compiler.
|
||||
-------- END-OF-HEADER ---------------------------------------------
|
||||
*/
|
||||
|
||||
.name JLINK_MONITOR_ISR
|
||||
.syntax unified
|
||||
|
||||
.extern JLINK_MONITOR_OnEnter
|
||||
.extern JLINK_MONITOR_OnExit
|
||||
.extern JLINK_MONITOR_OnPoll
|
||||
|
||||
.global DebugMon_Handler
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, configurable
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#define _MON_VERSION 100 // V x.yy
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, fixed
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#define _APP_SP_OFF_R0 0x00
|
||||
#define _APP_SP_OFF_R1 0x04
|
||||
#define _APP_SP_OFF_R2 0x08
|
||||
#define _APP_SP_OFF_R3 0x0C
|
||||
#define _APP_SP_OFF_R12 0x10
|
||||
#define _APP_SP_OFF_R14_LR 0x14
|
||||
#define _APP_SP_OFF_PC 0x18
|
||||
#define _APP_SP_OFF_XPSR 0x1C
|
||||
#define _APP_SP_OFF_S0 0x20
|
||||
#define _APP_SP_OFF_S1 0x24
|
||||
#define _APP_SP_OFF_S2 0x28
|
||||
#define _APP_SP_OFF_S3 0x2C
|
||||
#define _APP_SP_OFF_S4 0x30
|
||||
#define _APP_SP_OFF_S5 0x34
|
||||
#define _APP_SP_OFF_S6 0x38
|
||||
#define _APP_SP_OFF_S7 0x3C
|
||||
#define _APP_SP_OFF_S8 0x40
|
||||
#define _APP_SP_OFF_S9 0x44
|
||||
#define _APP_SP_OFF_S10 0x48
|
||||
#define _APP_SP_OFF_S11 0x4C
|
||||
#define _APP_SP_OFF_S12 0x50
|
||||
#define _APP_SP_OFF_S13 0x54
|
||||
#define _APP_SP_OFF_S14 0x58
|
||||
#define _APP_SP_OFF_S15 0x5C
|
||||
#define _APP_SP_OFF_FPSCR 0x60
|
||||
|
||||
#define _NUM_BYTES_BASIC_STACKFRAME 32
|
||||
#define _NUM_BYTES_EXTENDED_STACKFRAME 104 // Values for stackframes are explained at location where they are used
|
||||
|
||||
#define _SYSTEM_DCRDR_OFF 0x00
|
||||
#define _SYSTEM_DEMCR_OFF 0x04
|
||||
|
||||
#define _SYSTEM_DHCSR 0xE000EDF0 // Debug Halting Control and Status Register (DHCSR)
|
||||
#define _SYSTEM_DCRSR 0xE000EDF4 // Debug Core Register Selector Register (DCRSR)
|
||||
#define _SYSTEM_DCRDR 0xE000EDF8 // Debug Core Register Data Register (DCRDR)
|
||||
#define _SYSTEM_DEMCR 0xE000EDFC // Debug Exception and Monitor Control Register (DEMCR)
|
||||
|
||||
#define _SYSTEM_FPCCR 0xE000EF34 // Floating-Point Context Control Register (FPCCR)
|
||||
#define _SYSTEM_FPCAR 0xE000EF38 // Floating-Point Context Address Register (FPCAR)
|
||||
#define _SYSTEM_FPDSCR 0xE000EF3C // Floating-Point Default Status Control Register (FPDSCR)
|
||||
#define _SYSTEM_MVFR0 0xE000EF40 // Media and FP Feature Register 0 (MVFR0)
|
||||
#define _SYSTEM_MVFR1 0xE000EF44 // Media and FP Feature Register 1 (MVFR1)
|
||||
|
||||
/*
|
||||
* Defines for determining if the current debug config supports FPU registers
|
||||
* For some compilers like IAR EWARM when disabling the FPU in the compiler settings an error is thrown when
|
||||
*/
|
||||
#ifdef __FPU_PRESENT
|
||||
#if __FPU_PRESENT
|
||||
#define _HAS_FPU_REGS 1
|
||||
#else
|
||||
#define _HAS_FPU_REGS 0
|
||||
#endif
|
||||
#else
|
||||
#define _HAS_FPU_REGS 0
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Signature of monitor
|
||||
*
|
||||
* Function description
|
||||
* Needed for targets where also a boot ROM is present that possibly specifies a vector table with a valid debug monitor exception entry
|
||||
*/
|
||||
.section .text, "ax"
|
||||
|
||||
//
|
||||
// JLINKMONHANDLER
|
||||
//
|
||||
.byte 0x4A
|
||||
.byte 0x4C
|
||||
.byte 0x49
|
||||
.byte 0x4E
|
||||
.byte 0x4B
|
||||
.byte 0x4D
|
||||
.byte 0x4F
|
||||
.byte 0x4E
|
||||
.byte 0x48
|
||||
.byte 0x41
|
||||
.byte 0x4E
|
||||
.byte 0x44
|
||||
.byte 0x4C
|
||||
.byte 0x45
|
||||
.byte 0x52
|
||||
.byte 0x00 // Align to 8-bytes
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* DebugMon_Handler()
|
||||
*
|
||||
* Function description
|
||||
* Debug monitor handler. CPU enters this handler in case a "halt" request is made from the debugger.
|
||||
* This handler is also responsible for handling commands that are sent by the debugger.
|
||||
*
|
||||
* Notes
|
||||
* This is actually the ISR for the debug inerrupt (exception no. 12)
|
||||
*/
|
||||
.thumb_func
|
||||
|
||||
DebugMon_Handler:
|
||||
/*
|
||||
General procedure:
|
||||
DCRDR is used as communication register
|
||||
DEMCR[19] is used as ready flag
|
||||
For the command J-Link sends to the monitor: DCRDR[7:0] == Cmd, DCRDR[31:8] == ParamData
|
||||
|
||||
1) Monitor sets DEMCR[19] whenever it is ready to receive new commands/data
|
||||
DEMCR[19] is initially set on debug monitor entry
|
||||
2) J-Link will clear DEMCR[19] it has placed command/data in DCRDR for monitor
|
||||
3) Monitor will wait for DEMCR[19] to be cleared
|
||||
4) Monitor will process command (May cause additional data transfers etc., depends on command). Monitor will set DEMCR[19] whenever it has placed data for J-Link in the DCRDR
|
||||
5) No restart-CPU command? => Back to 2), Otherwise => 6)
|
||||
6) Monitor will clear DEMCR[19] 19 to indicate that it is no longer ready
|
||||
*/
|
||||
PUSH {LR}
|
||||
BL JLINK_MONITOR_OnEnter
|
||||
POP {LR}
|
||||
LDR.N R3,_AddrDCRDR // 0xe000edf8 == _SYSTEM_DCRDR
|
||||
B.N _IndicateMonReady
|
||||
_WaitProbeReadIndicateMonRdy: // while(_SYSTEM_DEMCR & (1uL << 19)); => Wait until J-Link has read item
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR
|
||||
LSLS R0,R0,#+12
|
||||
BMI.N _WaitProbeReadIndicateMonRdy
|
||||
_IndicateMonReady:
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR |= (1uL << 19); => Set MON_REQ bit, so J-Link knows monitor is ready to receive commands
|
||||
ORR R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
/*
|
||||
During command loop:
|
||||
R0 = Tmp
|
||||
R1 = Tmp
|
||||
R2 = Tmp
|
||||
R3 = &_SYSTEM_DCRDR (allows also access to DEMCR with offset)
|
||||
R12 = Tmp
|
||||
|
||||
Outside command loop R0-R3 and R12 may be overwritten by MONITOR_OnPoll()
|
||||
*/
|
||||
_WaitForJLinkCmd: // do {
|
||||
PUSH {LR}
|
||||
BL JLINK_MONITOR_OnPoll
|
||||
POP {LR}
|
||||
LDR.N R3,_AddrDCRDR // 0xe000edf8 == _SYSTEM_DCRDR
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
LSRS R0,R0,#+20 // DEMCR[19] -> Carry Clear? => J-Link has placed command for us
|
||||
BCS _WaitForJLinkCmd
|
||||
/*
|
||||
Perform command
|
||||
Command is placed by J-Link in DCRDR[7:0] and additional parameter data is stored in DCRDR[31:8]
|
||||
J-Link clears DEMCR[19] to indicate that it placed a command/data or read data
|
||||
Monitor sets DEMCR[19] to indicate that it placed data or read data / is ready for a new command
|
||||
Setting DEMCR[19] indicates "monitor ready for new command / data" and also indicates: "data has been placed in DCRDR by monitor, for J-Link"
|
||||
Therefore it is responsibility of the commands to respond to the commands accordingly
|
||||
|
||||
Commands for debug monitor
|
||||
Commands must not exceed 0xFF (255) as we only defined 8-bits for command-part. Higher 24-bits are parameter info for current command
|
||||
|
||||
Protocol for different commands:
|
||||
J-Link: Cmd -> DCRDR, DEMCR[19] -> 0 => Cmd placed by probe
|
||||
*/
|
||||
LDR R0,[R3, #+_SYSTEM_DCRDR_OFF] // ParamInfo = _SYSTEM_DCRDR
|
||||
LSRS R1,R0,#+8 // ParamInfo >>= 8
|
||||
LSLS R0,R0,#+24
|
||||
LSRS R0,R0,#+24 // Cmd = ParamInfo & 0xFF
|
||||
//
|
||||
// switch (Cmd)
|
||||
//
|
||||
CMP R0,#+0
|
||||
BEQ.N _HandleGetMonVersion // case _MON_CMD_GET_MONITOR_VERSION
|
||||
CMP R0,#+2
|
||||
BEQ.N _HandleReadReg // case _MON_CMD_READ_REG
|
||||
BCC.N _HandleRestartCPU // case _MON_CMD_RESTART_CPU
|
||||
CMP R0,#+3
|
||||
BEQ.N _HandleWriteReg_Veneer // case _MON_CMD_WRITE_REG
|
||||
B.N _IndicateMonReady // default : while (1);
|
||||
/*
|
||||
Return
|
||||
_MON_CMD_RESTART_CPU
|
||||
CPU: DEMCR[19] -> 0 => Monitor no longer ready
|
||||
*/
|
||||
_HandleRestartCPU:
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR &= ~(1uL << 19); => Clear MON_REQ to indicate that monitor is no longer active
|
||||
BIC R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
PUSH {LR}
|
||||
BL JLINK_MONITOR_OnExit
|
||||
POP {PC}
|
||||
//
|
||||
// Place data section here to not get in trouble with load-offsets
|
||||
//
|
||||
.section .text, "ax", %progbits
|
||||
.align 2
|
||||
_AddrDCRDR:
|
||||
.long 0xE000EDF8
|
||||
_AddrCPACR:
|
||||
.long 0xE000ED88
|
||||
|
||||
.section .text, "ax"
|
||||
.thumb_func
|
||||
|
||||
;/*********************************************************************
|
||||
;*
|
||||
;* _HandleGetMonVersion
|
||||
;*
|
||||
;*/
|
||||
_HandleGetMonVersion:
|
||||
/*
|
||||
_MON_CMD_GET_MONITOR_VERSION
|
||||
CPU: Data -> DCRDR, DEMCR[19] -> 1 => Data ready
|
||||
J-Link: DCRDR -> Read, DEMCR[19] -> 0 => Data read
|
||||
CPU: DEMCR[19] -> 1 => Mon ready
|
||||
*/
|
||||
MOVS R0,#+_MON_VERSION
|
||||
STR R0,[R3, #+_SYSTEM_DCRDR_OFF] // _SYSTEM_DCRDR = x
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR |= (1uL << 19); => Set MON_REQ bit, so J-Link knows monitor is ready to receive commands
|
||||
ORR R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF] // Indicate data ready
|
||||
B _WaitProbeReadIndicateMonRdy
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _HandleReadReg
|
||||
*
|
||||
*/
|
||||
_HandleWriteReg_Veneer:
|
||||
B.N _HandleWriteReg
|
||||
_HandleReadReg:
|
||||
/*
|
||||
_MON_CMD_READ_REG
|
||||
CPU: Data -> DCRDR, DEMCR[19] -> 1 => Data ready
|
||||
J-Link: DCRDR -> Read, DEMCR[19] -> 0 => Data read
|
||||
CPU: DEMCR[19] -> 1 => Mon ready
|
||||
|
||||
|
||||
Register indexes
|
||||
0-15: R0-R15 (13 == R13 reserved => is banked ... Has to be read as PSP / MSP. Decision has to be done by J-Link DLL side!)
|
||||
16: XPSR
|
||||
17: MSP
|
||||
18: PSP
|
||||
19: CFBP CONTROL/FAULTMASK/BASEPRI/PRIMASK (packed into 4 bytes of word. CONTROL = CFBP[31:24], FAULTMASK = CFBP[16:23], BASEPRI = CFBP[15:8], PRIMASK = CFBP[7:0]
|
||||
20: FPSCR
|
||||
21-52: FPS0-FPS31
|
||||
|
||||
|
||||
Register usage when entering this "subroutine":
|
||||
R0 Cmd
|
||||
R1 ParamInfo
|
||||
R2 ---
|
||||
R3 = &_SYSTEM_DCRDR (allows also access to DEMCR with offset)
|
||||
R12 ---
|
||||
|
||||
Table B1-9 EXC_RETURN definition of exception return behavior, with FP extension
|
||||
LR Return to Return SP Frame type
|
||||
---------------------------------------------------------
|
||||
0xFFFFFFE1 Handler mode. MSP Extended
|
||||
0xFFFFFFE9 Thread mode MSP Extended
|
||||
0xFFFFFFED Thread mode PSP Extended
|
||||
0xFFFFFFF1 Handler mode. MSP Basic
|
||||
0xFFFFFFF9 Thread mode MSP Basic
|
||||
0xFFFFFFFD Thread mode PSP Basic
|
||||
|
||||
So LR[2] == 1 => Return stack == PSP else MSP
|
||||
|
||||
R0-R3, R12, PC, xPSR can be read from application stackpointer
|
||||
Other regs can be read directly
|
||||
*/
|
||||
LSRS R2,LR,#+3 // Shift LR[2] into carry => Carry clear means that CPU was running on MSP
|
||||
ITE CS
|
||||
MRSCS R2,PSP
|
||||
MRSCC R2,MSP
|
||||
CMP R1,#+4 // if (RegIndex < 4) { (R0-R3)
|
||||
BCS _HandleReadRegR4
|
||||
LDR R0,[R2, R1, LSL #+2] // v = [SP + Rx * 4] (R0-R3)
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR4:
|
||||
CMP R1,#+5 // if (RegIndex < 5) { (R4)
|
||||
BCS _HandleReadRegR5
|
||||
MOV R0,R4
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR5:
|
||||
CMP R1,#+6 // if (RegIndex < 6) { (R5)
|
||||
BCS _HandleReadRegR6
|
||||
MOV R0,R5
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR6:
|
||||
CMP R1,#+7 // if (RegIndex < 7) { (R6)
|
||||
BCS _HandleReadRegR7
|
||||
MOV R0,R6
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR7:
|
||||
CMP R1,#+8 // if (RegIndex < 8) { (R7)
|
||||
BCS _HandleReadRegR8
|
||||
MOV R0,R7
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR8:
|
||||
CMP R1,#+9 // if (RegIndex < 9) { (R8)
|
||||
BCS _HandleReadRegR9
|
||||
MOV R0,R8
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR9:
|
||||
CMP R1,#+10 // if (RegIndex < 10) { (R9)
|
||||
BCS _HandleReadRegR10
|
||||
MOV R0,R9
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR10:
|
||||
CMP R1,#+11 // if (RegIndex < 11) { (R10)
|
||||
BCS _HandleReadRegR11
|
||||
MOV R0,R10
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR11:
|
||||
CMP R1,#+12 // if (RegIndex < 12) { (R11)
|
||||
BCS _HandleReadRegR12
|
||||
MOV R0,R11
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR12:
|
||||
CMP R1,#+14 // if (RegIndex < 14) { (R12)
|
||||
BCS _HandleReadRegR14
|
||||
LDR R0,[R2, #+_APP_SP_OFF_R12]
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR14:
|
||||
CMP R1,#+15 // if (RegIndex < 15) { (R14 / LR)
|
||||
BCS _HandleReadRegR15
|
||||
LDR R0,[R2, #+_APP_SP_OFF_R14_LR]
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegR15:
|
||||
CMP R1,#+16 // if (RegIndex < 16) { (R15 / PC)
|
||||
BCS _HandleReadRegXPSR
|
||||
LDR R0,[R2, #+_APP_SP_OFF_PC]
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegXPSR:
|
||||
CMP R1,#+17 // if (RegIndex < 17) { (xPSR)
|
||||
BCS _HandleReadRegMSP
|
||||
LDR R0,[R2, #+_APP_SP_OFF_XPSR]
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegMSP:
|
||||
/*
|
||||
Stackpointer is tricky because we need to get some info about the SP used in the user app, first
|
||||
|
||||
Handle reading R0-R3 which can be read right from application stackpointer
|
||||
|
||||
Table B1-9 EXC_RETURN definition of exception return behavior, with FP extension
|
||||
LR Return to Return SP Frame type
|
||||
---------------------------------------------------------
|
||||
0xFFFFFFE1 Handler mode. MSP Extended
|
||||
0xFFFFFFE9 Thread mode MSP Extended
|
||||
0xFFFFFFED Thread mode PSP Extended
|
||||
0xFFFFFFF1 Handler mode. MSP Basic
|
||||
0xFFFFFFF9 Thread mode MSP Basic
|
||||
0xFFFFFFFD Thread mode PSP Basic
|
||||
|
||||
So LR[2] == 1 => Return stack == PSP else MSP
|
||||
Per architecture definition: Inside monitor (exception) SP = MSP
|
||||
|
||||
Stack pointer handling is complicated because it is different what is pushed on the stack before entering the monitor ISR...
|
||||
Cortex-M: 8 regs
|
||||
Cortex-M + forced-stack-alignment: 8 regs + 1 dummy-word if stack was not 8-byte aligned
|
||||
Cortex-M + FPU: 8 regs + 17 FPU regs + 1 dummy-word + 1-dummy word if stack was not 8-byte aligned
|
||||
Cortex-M + FPU + lazy mode: 8 regs + 17 dummy-words + 1 dummy-word + 1-dummy word if stack was not 8-byte aligned
|
||||
*/
|
||||
CMP R1,#+18 // if (RegIndex < 18) { (MSP)
|
||||
BCS _HandleReadRegPSP
|
||||
MRS R0,MSP
|
||||
LSRS R1,LR,#+3 // LR[2] -> Carry == 0 => CPU was running on MSP => Needs correction
|
||||
BCS _HandleReadRegDone_Veneer // CPU was running on PSP? => No correction necessary
|
||||
_HandleSPCorrection:
|
||||
LSRS R1,LR,#+5 // LR[4] -> Carry == 0 => extended stack frame has been allocated. See ARM DDI0403D, B1.5.7 Stack alignment on exception entry
|
||||
ITE CS
|
||||
ADDCS R0,R0,#+_NUM_BYTES_BASIC_STACKFRAME
|
||||
ADDCC R0,R0,#+_NUM_BYTES_EXTENDED_STACKFRAME
|
||||
LDR R1,[R2, #+_APP_SP_OFF_XPSR] // Get xPSR from application stack (R2 has been set to app stack on beginning of _HandleReadReg)
|
||||
LSRS R1,R1,#+5 // xPSR[9] -> Carry == 1 => Stack has been force-aligned before pushing regs. See ARM DDI0403D, B1.5.7 Stack alignment on exception entry
|
||||
IT CS
|
||||
ADDCS R0,R0,#+4
|
||||
B _HandleReadRegDone
|
||||
_HandleReadRegPSP: // RegIndex == 18
|
||||
CMP R1,#+19 // if (RegIndex < 19) {
|
||||
BCS _HandleReadRegCFBP
|
||||
MRS R0,PSP // PSP is not touched by monitor
|
||||
LSRS R1,LR,#+3 // LR[2] -> Carry == 1 => CPU was running on PSP => Needs correction
|
||||
BCC _HandleReadRegDone_Veneer // CPU was running on MSP? => No correction of PSP necessary
|
||||
B _HandleSPCorrection
|
||||
_HandleReadRegCFBP:
|
||||
/*
|
||||
CFBP is a register that can only be read via debug probe and is a merger of the following regs:
|
||||
CONTROL/FAULTMASK/BASEPRI/PRIMASK (packed into 4 bytes of word. CONTROL = CFBP[31:24], FAULTMASK = CFBP[16:23], BASEPRI = CFBP[15:8], PRIMASK = CFBP[7:0]
|
||||
To keep J-Link side the same for monitor and halt mode, we also return CFBP in monitor mode
|
||||
*/
|
||||
CMP R1,#+20 // if (RegIndex < 20) { (CFBP)
|
||||
BCS _HandleReadRegFPU
|
||||
MOVS R0,#+0
|
||||
MRS R2,PRIMASK
|
||||
ORRS R0,R2 // Merge PRIMASK into CFBP[7:0]
|
||||
MRS R2,BASEPRI
|
||||
LSLS R2,R2,#+8 // Merge BASEPRI into CFBP[15:8]
|
||||
ORRS R0,R2
|
||||
MRS R2,FAULTMASK
|
||||
LSLS R2,R2,#+16 // Merge FAULTMASK into CFBP[23:16]
|
||||
ORRS R0,R2
|
||||
MRS R2,CONTROL
|
||||
LSRS R1,LR,#3 // LR[2] -> Carry. CONTROL.SPSEL is saved to LR[2] on exception entry => ARM DDI0403D, B1.5.6 Exception entry behavior
|
||||
IT CS // As J-Link sees value of CONTROL at application time, we need reconstruct original value of CONTROL
|
||||
ORRCS R2,R2,#+2 // CONTROL.SPSEL (CONTROL[1]) == 0 inside monitor
|
||||
LSRS R1,LR,#+5 // LR[4] == NOT(CONTROL.FPCA) -> Carry
|
||||
ITE CS // Merge original value of FPCA (CONTROL[2]) into read data
|
||||
BICCS R2,R2,#+0x04 // Remember LR contains NOT(CONTROL)
|
||||
ORRCC R2,R2,#+0x04
|
||||
LSLS R2,R2,#+24
|
||||
ORRS R0,R2
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegFPU:
|
||||
#if _HAS_FPU_REGS
|
||||
CMP R1,#+53 // if (RegIndex < 53) { (20 (FPSCR), 21-52 FPS0-FPS31)
|
||||
BCS _HandleReadRegDone_Veneer
|
||||
/*
|
||||
Read Coprocessor Access Control Register (CPACR) to check if CP10 and CP11 are enabled
|
||||
If not, access to floating point is not possible
|
||||
CPACR[21:20] == CP10 enable. 0b01 = Privileged access only. 0b11 = Full access. Other = reserved
|
||||
CPACR[23:22] == CP11 enable. 0b01 = Privileged access only. 0b11 = Full access. Other = reserved
|
||||
*/
|
||||
LDR R0,_AddrCPACR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+8
|
||||
LSRS R0,R0,#+28
|
||||
CMP R0,#+0xF
|
||||
BEQ _HandleReadRegFPU_Allowed
|
||||
CMP R0,#+0x5
|
||||
BNE _HandleReadRegDone_Veneer
|
||||
_HandleReadRegFPU_Allowed:
|
||||
CMP R1,#+21 // if (RegIndex < 21) (20 == FPSCR)
|
||||
BCS _HandleReadRegFPS0_FPS31
|
||||
LSRS R0,LR,#+5 // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BCS _HandleReadFPSCRLazyMode // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
LDR R0,=_SYSTEM_FPCCR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+2 // FPCCR[30] -> Carry == 1 indicates if lazy mode is active, so space on stack is reserved but FPU registers are not saved on stack
|
||||
BCS _HandleReadFPSCRLazyMode
|
||||
LDR R0,[R2, #+_APP_SP_OFF_FPSCR]
|
||||
B _HandleReadRegDone
|
||||
_HandleReadFPSCRLazyMode:
|
||||
VMRS R0,FPSCR
|
||||
B _HandleReadRegDone
|
||||
_HandleReadRegFPS0_FPS31: // RegIndex == 21-52
|
||||
LSRS R0,LR,#+5 // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BCS _HandleReadFPS0_FPS31LazyMode // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
LDR R0,=_SYSTEM_FPCCR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+2 // FPCCR[30] -> Carry == 1 indicates if lazy mode is active, so space on stack is reserved but FPU registers are not saved on stack
|
||||
BCS _HandleReadFPS0_FPS31LazyMode
|
||||
SUBS R1,#+21 // Convert absolute reg index into rel. one
|
||||
LSLS R1,R1,#+2 // RegIndex to position on stack
|
||||
ADDS R1,#+_APP_SP_OFF_S0
|
||||
LDR R0,[R2, R1]
|
||||
_HandleReadRegDone_Veneer:
|
||||
B _HandleReadRegDone
|
||||
_HandleReadFPS0_FPS31LazyMode:
|
||||
SUBS R1,#+20 // convert abs. RegIndex into rel. one
|
||||
MOVS R0,#+6
|
||||
MULS R1,R0,R1
|
||||
LDR R0,=_HandleReadRegUnknown
|
||||
SUB R0,R0,R1 // _HandleReadRegUnknown - 6 * ((RegIndex - 21) + 1)
|
||||
ORR R0,R0,#1 // Thumb bit needs to be set in DestAddr
|
||||
BX R0
|
||||
//
|
||||
// Table for reading FPS0-FPS31
|
||||
//
|
||||
VMOV R0,S31 // v = FPSx
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S30
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S29
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S28
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S27
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S26
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S25
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S24
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S23
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S22
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S21
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S20
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S19
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S18
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S17
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S16
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S15
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S14
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S13
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S12
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S11
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S10
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S9
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S8
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S7
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S6
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S5
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S4
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S3
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S2
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S1
|
||||
B _HandleReadRegDone
|
||||
VMOV R0,S0
|
||||
B _HandleReadRegDone
|
||||
#else
|
||||
B _HandleReadRegUnknown
|
||||
_HandleReadRegDone_Veneer:
|
||||
B _HandleReadRegDone
|
||||
#endif
|
||||
_HandleReadRegUnknown:
|
||||
MOVS R0,#+0 // v = 0
|
||||
B.N _HandleReadRegDone
|
||||
_HandleReadRegDone:
|
||||
|
||||
// Send register content to J-Link and wait until J-Link has read the data
|
||||
|
||||
STR R0,[R3, #+_SYSTEM_DCRDR_OFF] // DCRDR = v;
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR |= (1uL << 19); => Set MON_REQ bit, so J-Link knows monitor is ready to receive commands
|
||||
ORR R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF] // Indicate data ready
|
||||
B _WaitProbeReadIndicateMonRdy
|
||||
|
||||
// Data section for register addresses
|
||||
|
||||
_HandleWriteReg:
|
||||
/*
|
||||
_MON_CMD_WRITE_REG
|
||||
CPU: DEMCR[19] -> 1 => Mon ready
|
||||
J-Link: Data -> DCRDR, DEMCR[19] -> 0 => Data placed by probe
|
||||
CPU: DCRDR -> Read, Process command, DEMCR[19] -> 1 => Data read & mon ready
|
||||
|
||||
Register indexes
|
||||
0-15: R0-R15 (13 == R13 reserved => is banked ... Has to be read as PSP / MSP. Decision has to be done by J-Link DLL side!)
|
||||
16: XPSR
|
||||
17: MSP
|
||||
18: PSP
|
||||
19: CFBP CONTROL/FAULTMASK/BASEPRI/PRIMASK (packed into 4 bytes of word. CONTROL = CFBP[31:24], FAULTMASK = CFBP[16:23], BASEPRI = CFBP[15:8], PRIMASK = CFBP[7:0]
|
||||
20: FPSCR
|
||||
21-52: FPS0-FPS31
|
||||
|
||||
|
||||
Register usage when entering this "subroutine":
|
||||
R0 Cmd
|
||||
R1 ParamInfo
|
||||
R2 ---
|
||||
R3 = &_SYSTEM_DCRDR (allows also access to DEMCR with offset)
|
||||
R12 ---
|
||||
|
||||
Table B1-9 EXC_RETURN definition of exception return behavior, with FP extension
|
||||
LR Return to Return SP Frame type
|
||||
---------------------------------------------------------
|
||||
0xFFFFFFE1 Handler mode. MSP Extended
|
||||
0xFFFFFFE9 Thread mode MSP Extended
|
||||
0xFFFFFFED Thread mode PSP Extended
|
||||
0xFFFFFFF1 Handler mode. MSP Basic
|
||||
0xFFFFFFF9 Thread mode MSP Basic
|
||||
0xFFFFFFFD Thread mode PSP Basic
|
||||
|
||||
So LR[2] == 1 => Return stack == PSP else MSP
|
||||
|
||||
R0-R3, R12, PC, xPSR can be written via application stackpointer
|
||||
Other regs can be written directly
|
||||
|
||||
|
||||
Read register data from J-Link into R0
|
||||
*/
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF] // _SYSTEM_DEMCR |= (1uL << 19); => Monitor is ready to receive register data
|
||||
ORR R0,R0,#0x80000
|
||||
STR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
_HandleWRegWaitUntilDataRecv:
|
||||
LDR R0,[R3, #+_SYSTEM_DEMCR_OFF]
|
||||
LSLS R0,R0,#+12
|
||||
BMI.N _HandleWRegWaitUntilDataRecv // DEMCR[19] == 0 => J-Link has placed new data for us
|
||||
LDR R0,[R3, #+_SYSTEM_DCRDR_OFF] // Get register data
|
||||
//
|
||||
// Determine application SP
|
||||
//
|
||||
LSRS R2,LR,#+3 // Shift LR[2] into carry => Carry clear means that CPU was running on MSP
|
||||
ITE CS
|
||||
MRSCS R2,PSP
|
||||
MRSCC R2,MSP
|
||||
CMP R1,#+4 // if (RegIndex < 4) { (R0-R3)
|
||||
BCS _HandleWriteRegR4
|
||||
STR R0,[R2, R1, LSL #+2] // v = [SP + Rx * 4] (R0-R3)
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR4:
|
||||
CMP R1,#+5 // if (RegIndex < 5) { (R4)
|
||||
BCS _HandleWriteRegR5
|
||||
MOV R4,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR5:
|
||||
CMP R1,#+6 // if (RegIndex < 6) { (R5)
|
||||
BCS _HandleWriteRegR6
|
||||
MOV R5,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR6:
|
||||
CMP R1,#+7 // if (RegIndex < 7) { (R6)
|
||||
BCS _HandleWriteRegR7
|
||||
MOV R6,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR7:
|
||||
CMP R1,#+8 // if (RegIndex < 8) { (R7)
|
||||
BCS _HandleWriteRegR8
|
||||
MOV R7,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR8:
|
||||
CMP R1,#+9 // if (RegIndex < 9) { (R8)
|
||||
BCS _HandleWriteRegR9
|
||||
MOV R8,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR9:
|
||||
CMP R1,#+10 // if (RegIndex < 10) { (R9)
|
||||
BCS _HandleWriteRegR10
|
||||
MOV R9,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR10:
|
||||
CMP R1,#+11 // if (RegIndex < 11) { (R10)
|
||||
BCS _HandleWriteRegR11
|
||||
MOV R10,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR11:
|
||||
CMP R1,#+12 // if (RegIndex < 12) { (R11)
|
||||
BCS _HandleWriteRegR12
|
||||
MOV R11,R0
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR12:
|
||||
CMP R1,#+14 // if (RegIndex < 14) { (R12)
|
||||
BCS _HandleWriteRegR14
|
||||
STR R0,[R2, #+_APP_SP_OFF_R12]
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR14:
|
||||
CMP R1,#+15 // if (RegIndex < 15) { (R14 / LR)
|
||||
BCS _HandleWriteRegR15
|
||||
STR R0,[R2, #+_APP_SP_OFF_R14_LR]
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegR15:
|
||||
CMP R1,#+16 // if (RegIndex < 16) { (R15 / PC)
|
||||
BCS _HandleWriteRegXPSR
|
||||
STR R0,[R2, #+_APP_SP_OFF_PC]
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegXPSR:
|
||||
CMP R1,#+17 // if (RegIndex < 17) { (xPSR)
|
||||
BCS _HandleWriteRegMSP
|
||||
STR R0,[R2, #+_APP_SP_OFF_XPSR]
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegMSP:
|
||||
//
|
||||
// For now, SP cannot be modified because it is needed to jump back from monitor mode
|
||||
//
|
||||
CMP R1,#+18 // if (RegIndex < 18) { (MSP)
|
||||
BCS _HandleWriteRegPSP
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegPSP: // RegIndex == 18
|
||||
CMP R1,#+19 // if (RegIndex < 19) {
|
||||
BCS _HandleWriteRegCFBP
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegCFBP:
|
||||
/*
|
||||
CFBP is a register that can only be read via debug probe and is a merger of the following regs:
|
||||
CONTROL/FAULTMASK/BASEPRI/PRIMASK (packed into 4 bytes of word. CONTROL = CFBP[31:24], FAULTMASK = CFBP[16:23], BASEPRI = CFBP[15:8], PRIMASK = CFBP[7:0]
|
||||
To keep J-Link side the same for monitor and halt mode, we also return CFBP in monitor mode
|
||||
*/
|
||||
CMP R1,#+20 // if (RegIndex < 20) { (CFBP)
|
||||
BCS _HandleWriteRegFPU
|
||||
LSLS R1,R0,#+24
|
||||
LSRS R1,R1,#+24 // Extract CFBP[7:0] => PRIMASK
|
||||
MSR PRIMASK,R1
|
||||
LSLS R1,R0,#+16
|
||||
LSRS R1,R1,#+24 // Extract CFBP[15:8] => BASEPRI
|
||||
MSR BASEPRI,R1
|
||||
LSLS R1,R0,#+8 // Extract CFBP[23:16] => FAULTMASK
|
||||
LSRS R1,R1,#+24
|
||||
MSR FAULTMASK,R1
|
||||
LSRS R1,R0,#+24 // Extract CFBP[31:24] => CONTROL
|
||||
LSRS R0,R1,#2 // Current CONTROL[1] -> Carry
|
||||
ITE CS // Update saved CONTROL.SPSEL (CONTROL[1]). CONTROL.SPSEL is saved to LR[2] on exception entry => ARM DDI0403D, B1.5.6 Exception entry behavior
|
||||
ORRCS LR,LR,#+4
|
||||
BICCC LR,LR,#+4
|
||||
BIC R1,R1,#+2 // CONTROL.SPSEL (CONTROL[1]) == 0 inside monitor. Otherwise behavior is UNPREDICTABLE
|
||||
LSRS R0,R1,#+3 // New CONTROL.FPCA (CONTROL[2]) -> Carry
|
||||
ITE CS // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BICCS LR,LR,#+0x10 // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
ORRCC LR,LR,#+0x10
|
||||
MRS R0,CONTROL
|
||||
LSRS R0,R0,#+3 // CONTROL[2] -> Carry
|
||||
ITE CS // Preserve original value of current CONTROL[2]
|
||||
ORRCS R1,R1,#+0x04
|
||||
BICCC R1,R1,#+0x04
|
||||
MSR CONTROL,R1
|
||||
ISB // Necessary after writing to CONTROL, see ARM DDI0403D, B1.4.4 The special-purpose CONTROL register
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegFPU:
|
||||
#if _HAS_FPU_REGS
|
||||
CMP R1,#+53 // if (RegIndex < 53) { (20 (FPSCR), 21-52 FPS0-FPS31)
|
||||
BCS _HandleWriteRegDone_Veneer
|
||||
/*
|
||||
Read Coprocessor Access Control Register (CPACR) to check if CP10 and CP11 are enabled
|
||||
If not, access to floating point is not possible
|
||||
CPACR[21:20] == CP10 enable. 0b01 = Privileged access only. 0b11 = Full access. Other = reserved
|
||||
CPACR[23:22] == CP11 enable. 0b01 = Privileged access only. 0b11 = Full access. Other = reserved
|
||||
*/
|
||||
MOV R12,R0 // Save register data
|
||||
LDR R0,_AddrCPACR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+8
|
||||
LSRS R0,R0,#+28
|
||||
CMP R0,#+0xF
|
||||
BEQ _HandleWriteRegFPU_Allowed
|
||||
CMP R0,#+0x5
|
||||
BNE _HandleWriteRegDone_Veneer
|
||||
_HandleWriteRegFPU_Allowed:
|
||||
CMP R1,#+21 // if (RegIndex < 21) (20 == FPSCR)
|
||||
BCS _HandleWriteRegFPS0_FPS31
|
||||
LSRS R0,LR,#+5 // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BCS _HandleWriteFPSCRLazyMode // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
LDR R0,=_SYSTEM_FPCCR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+2 // FPCCR[30] -> Carry == 1 indicates if lazy mode is active, so space on stack is reserved but FPU registers are not saved on stack
|
||||
BCS _HandleWriteFPSCRLazyMode
|
||||
STR R12,[R2, #+_APP_SP_OFF_FPSCR]
|
||||
B _HandleWriteRegDone
|
||||
_HandleWriteFPSCRLazyMode:
|
||||
VMSR FPSCR,R12
|
||||
B _HandleWriteRegDone
|
||||
_HandleWriteRegFPS0_FPS31: // RegIndex == 21-52
|
||||
LDR R0,=_SYSTEM_FPCCR
|
||||
LDR R0,[R0]
|
||||
LSLS R0,R0,#+2 // FPCCR[30] -> Carry == 1 indicates if lazy mode is active, so space on stack is reserved but FPU registers are not saved on stack
|
||||
BCS _HandleWriteFPS0_FPS31LazyMode
|
||||
LSRS R0,LR,#+5 // CONTROL[2] == FPCA => NOT(FPCA) saved to LR[4]. LR[4] == 0 => Extended stack frame, so FPU regs possibly on stack
|
||||
BCS _HandleWriteFPS0_FPS31LazyMode // Remember: NOT(FPCA) is stored to LR. == 0 means: Extended stack frame
|
||||
SUBS R1,#+21 // Convert absolute reg index into rel. one
|
||||
LSLS R1,R1,#+2 // RegIndex to position on stack
|
||||
ADDS R1,#+_APP_SP_OFF_S0
|
||||
STR R12,[R2, R1]
|
||||
_HandleWriteRegDone_Veneer:
|
||||
B _HandleWriteRegDone
|
||||
_HandleWriteFPS0_FPS31LazyMode:
|
||||
SUBS R1,#+20 // Convert abs. RegIndex into rel. one
|
||||
MOVS R0,#+6
|
||||
MULS R1,R0,R1
|
||||
LDR R0,=_HandleReadRegUnknown
|
||||
SUB R0,R0,R1 // _HandleReadRegUnknown - 6 * ((RegIndex - 21) + 1)
|
||||
ORR R0,R0,#1 // Thumb bit needs to be set in DestAddr
|
||||
BX R0
|
||||
//
|
||||
// Table for reading FPS0-FPS31
|
||||
//
|
||||
VMOV S31,R12 // v = FPSx
|
||||
B _HandleWriteRegDone
|
||||
VMOV S30,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S29,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S28,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S27,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S26,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S25,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S24,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S23,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S22,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S21,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S20,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S19,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S18,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S17,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S16,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S15,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S14,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S13,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S12,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S11,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S10,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S9,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S8,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S7,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S6,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S5,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S4,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S3,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S2,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S1,R12
|
||||
B _HandleWriteRegDone
|
||||
VMOV S0,R12
|
||||
B _HandleWriteRegDone
|
||||
#else
|
||||
B _HandleWriteRegUnknown
|
||||
#endif
|
||||
_HandleWriteRegUnknown:
|
||||
B.N _HandleWriteRegDone
|
||||
_HandleWriteRegDone:
|
||||
B _IndicateMonReady // Indicate that monitor has read data, processed command and is ready for a new one
|
||||
.end
|
||||
/****** End Of File *************************************************/
|
@ -0,0 +1,280 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2014 - 2020 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* - Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* - Neither the name of SEGGER Microcontroller GmbH *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. *
|
||||
* IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : SEGGER_HardFaultHandler.c
|
||||
Purpose : Generic SEGGER HardFault handler for Cortex-M
|
||||
Literature:
|
||||
[1] Analyzing HardFaults on Cortex-M CPUs (https://www.segger.com/downloads/appnotes/AN00016_AnalyzingHardFaultsOnCortexM.pdf)
|
||||
|
||||
Additional information:
|
||||
This HardFault handler enables user-friendly analysis of hard faults
|
||||
in debug configurations.
|
||||
If a release configuration requires a HardFault handler,
|
||||
a specific HardFault handler should be included instead,
|
||||
which for example issues a reset or lits an error LED.
|
||||
-------- END-OF-HEADER ---------------------------------------------
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#define SYSHND_CTRL (*(volatile unsigned int*) (0xE000ED24u)) // System Handler Control and State Register
|
||||
#define NVIC_MFSR (*(volatile unsigned char*) (0xE000ED28u)) // Memory Management Fault Status Register
|
||||
#define NVIC_BFSR (*(volatile unsigned char*) (0xE000ED29u)) // Bus Fault Status Register
|
||||
#define NVIC_UFSR (*(volatile unsigned short*)(0xE000ED2Au)) // Usage Fault Status Register
|
||||
#define NVIC_HFSR (*(volatile unsigned int*) (0xE000ED2Cu)) // Hard Fault Status Register
|
||||
#define NVIC_DFSR (*(volatile unsigned int*) (0xE000ED30u)) // Debug Fault Status Register
|
||||
#define NVIC_BFAR (*(volatile unsigned int*) (0xE000ED38u)) // Bus Fault Manage Address Register
|
||||
#define NVIC_AFSR (*(volatile unsigned int*) (0xE000ED3Cu)) // Auxiliary Fault Status Register
|
||||
|
||||
#ifndef DEBUG // Should be overwritten by project settings
|
||||
#define DEBUG (0) // in debug builds
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Prototypes
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void HardFaultHandler(unsigned int* pStack);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Static data
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#if DEBUG
|
||||
static volatile unsigned int _Continue; // Set this variable to 1 to run further
|
||||
|
||||
static struct {
|
||||
struct {
|
||||
volatile unsigned int r0; // Register R0
|
||||
volatile unsigned int r1; // Register R1
|
||||
volatile unsigned int r2; // Register R2
|
||||
volatile unsigned int r3; // Register R3
|
||||
volatile unsigned int r12; // Register R12
|
||||
volatile unsigned int lr; // Link register
|
||||
volatile unsigned int pc; // Program counter
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int IPSR : 8; // Interrupt Program Status register (IPSR)
|
||||
unsigned int EPSR : 19; // Execution Program Status register (EPSR)
|
||||
unsigned int APSR : 5; // Application Program Status register (APSR)
|
||||
} bits;
|
||||
} psr; // Program status register.
|
||||
} SavedRegs;
|
||||
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault is active
|
||||
unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active
|
||||
unsigned int UnusedBits1 : 1;
|
||||
unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception is active
|
||||
unsigned int UnusedBits2 : 3;
|
||||
unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active
|
||||
unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception is active
|
||||
unsigned int UnusedBits3 : 1;
|
||||
unsigned int PENDSVACT : 1; // Read as 1 if PendSV exception is active
|
||||
unsigned int SYSTICKACT : 1; // Read as 1 if SYSTICK exception is active
|
||||
unsigned int USGFAULTPENDED : 1; // Usage fault pended; usage fault started but was replaced by a higher-priority exception
|
||||
unsigned int MEMFAULTPENDED : 1; // Memory management fault pended; memory management fault started but was replaced by a higher-priority exception
|
||||
unsigned int BUSFAULTPENDED : 1; // Bus fault pended; bus fault handler was started but was replaced by a higher-priority exception
|
||||
unsigned int SVCALLPENDED : 1; // SVC pended; SVC was started but was replaced by a higher-priority exception
|
||||
unsigned int MEMFAULTENA : 1; // Memory management fault handler enable
|
||||
unsigned int BUSFAULTENA : 1; // Bus fault handler enable
|
||||
unsigned int USGFAULTENA : 1; // Usage fault handler enable
|
||||
} bits;
|
||||
} syshndctrl; // System Handler Control and State Register (0xE000ED24)
|
||||
|
||||
union {
|
||||
volatile unsigned char byte;
|
||||
struct {
|
||||
unsigned char IACCVIOL : 1; // Instruction access violation
|
||||
unsigned char DACCVIOL : 1; // Data access violation
|
||||
unsigned char UnusedBits : 1;
|
||||
unsigned char MUNSTKERR : 1; // Unstacking error
|
||||
unsigned char MSTKERR : 1; // Stacking error
|
||||
unsigned char UnusedBits2 : 2;
|
||||
unsigned char MMARVALID : 1; // Indicates the MMAR is valid
|
||||
} bits;
|
||||
} mfsr; // Memory Management Fault Status Register (0xE000ED28)
|
||||
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int IBUSERR : 1; // Instruction access violation
|
||||
unsigned int PRECISERR : 1; // Precise data access violation
|
||||
unsigned int IMPREISERR : 1; // Imprecise data access violation
|
||||
unsigned int UNSTKERR : 1; // Unstacking error
|
||||
unsigned int STKERR : 1; // Stacking error
|
||||
unsigned int UnusedBits : 2;
|
||||
unsigned int BFARVALID : 1; // Indicates BFAR is valid
|
||||
} bits;
|
||||
} bfsr; // Bus Fault Status Register (0xE000ED29)
|
||||
volatile unsigned int bfar; // Bus Fault Manage Address Register (0xE000ED38)
|
||||
|
||||
union {
|
||||
volatile unsigned short byte;
|
||||
struct {
|
||||
unsigned short UNDEFINSTR : 1; // Attempts to execute an undefined instruction
|
||||
unsigned short INVSTATE : 1; // Attempts to switch to an invalid state (e.g., ARM)
|
||||
unsigned short INVPC : 1; // Attempts to do an exception with a bad value in the EXC_RETURN number
|
||||
unsigned short NOCP : 1; // Attempts to execute a coprocessor instruction
|
||||
unsigned short UnusedBits : 4;
|
||||
unsigned short UNALIGNED : 1; // Indicates that an unaligned access fault has taken place
|
||||
unsigned short DIVBYZERO : 1; // Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)
|
||||
} bits;
|
||||
} ufsr; // Usage Fault Status Register (0xE000ED2A)
|
||||
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int UnusedBits : 1;
|
||||
unsigned int VECTBL : 1; // Indicates hard fault is caused by failed vector fetch
|
||||
unsigned int UnusedBits2 : 28;
|
||||
unsigned int FORCED : 1; // Indicates hard fault is taken because of bus fault/memory management fault/usage fault
|
||||
unsigned int DEBUGEVT : 1; // Indicates hard fault is triggered by debug event
|
||||
} bits;
|
||||
} hfsr; // Hard Fault Status Register (0xE000ED2C)
|
||||
|
||||
union {
|
||||
volatile unsigned int byte;
|
||||
struct {
|
||||
unsigned int HALTED : 1; // Halt requested in NVIC
|
||||
unsigned int BKPT : 1; // BKPT instruction executed
|
||||
unsigned int DWTTRAP : 1; // DWT match occurred
|
||||
unsigned int VCATCH : 1; // Vector fetch occurred
|
||||
unsigned int EXTERNAL : 1; // EDBGRQ signal asserted
|
||||
} bits;
|
||||
} dfsr; // Debug Fault Status Register (0xE000ED30)
|
||||
|
||||
volatile unsigned int afsr; // Auxiliary Fault Status Register (0xE000ED3C), Vendor controlled (optional)
|
||||
} HardFaultRegs;
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Global functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* HardFaultHandler()
|
||||
*
|
||||
* Function description
|
||||
* C part of the hard fault handler which is called by the assembler
|
||||
* function HardFault_Handler
|
||||
*/
|
||||
void HardFaultHandler(unsigned int* pStack) {
|
||||
//
|
||||
// In case we received a hard fault because of a breakpoint instruction, we return.
|
||||
// This may happen when using semihosting for printf outputs and no debugger is connected,
|
||||
// i.e. when running a "Debug" configuration in release mode.
|
||||
//
|
||||
if (NVIC_HFSR & (1u << 31)) {
|
||||
NVIC_HFSR |= (1u << 31); // Reset Hard Fault status
|
||||
*(pStack + 6u) += 2u; // PC is located on stack at SP + 24 bytes. Increment PC by 2 to skip break instruction.
|
||||
return; // Return to interrupted application
|
||||
}
|
||||
#if DEBUG
|
||||
//
|
||||
// Read NVIC registers
|
||||
//
|
||||
HardFaultRegs.syshndctrl.byte = SYSHND_CTRL; // System Handler Control and State Register
|
||||
HardFaultRegs.mfsr.byte = NVIC_MFSR; // Memory Fault Status Register
|
||||
HardFaultRegs.bfsr.byte = NVIC_BFSR; // Bus Fault Status Register
|
||||
HardFaultRegs.bfar = NVIC_BFAR; // Bus Fault Manage Address Register
|
||||
HardFaultRegs.ufsr.byte = NVIC_UFSR; // Usage Fault Status Register
|
||||
HardFaultRegs.hfsr.byte = NVIC_HFSR; // Hard Fault Status Register
|
||||
HardFaultRegs.dfsr.byte = NVIC_DFSR; // Debug Fault Status Register
|
||||
HardFaultRegs.afsr = NVIC_AFSR; // Auxiliary Fault Status Register
|
||||
//
|
||||
// Halt execution
|
||||
// If NVIC registers indicate readable memory, change the variable value to != 0 to continue execution.
|
||||
//
|
||||
_Continue = 0u;
|
||||
while (_Continue == 0u) {
|
||||
}
|
||||
//
|
||||
// Read saved registers from the stack.
|
||||
//
|
||||
HardFaultRegs.SavedRegs.r0 = pStack[0]; // Register R0
|
||||
HardFaultRegs.SavedRegs.r1 = pStack[1]; // Register R1
|
||||
HardFaultRegs.SavedRegs.r2 = pStack[2]; // Register R2
|
||||
HardFaultRegs.SavedRegs.r3 = pStack[3]; // Register R3
|
||||
HardFaultRegs.SavedRegs.r12 = pStack[4]; // Register R12
|
||||
HardFaultRegs.SavedRegs.lr = pStack[5]; // Link register LR
|
||||
HardFaultRegs.SavedRegs.pc = pStack[6]; // Program counter PC
|
||||
HardFaultRegs.SavedRegs.psr.byte = pStack[7]; // Program status word PSR
|
||||
//
|
||||
// Halt execution
|
||||
// To step out of the HardFaultHandler, change the variable value to != 0.
|
||||
//
|
||||
_Continue = 0u;
|
||||
while (_Continue == 0u) {
|
||||
}
|
||||
#else
|
||||
//
|
||||
// If this module is included in a release configuration, simply stay in the HardFault handler
|
||||
//
|
||||
(void)pStack;
|
||||
do {
|
||||
} while (1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************** End of file ****************************/
|
@ -0,0 +1,24 @@
|
||||
#ifndef _TREZOR_T3W1_H
|
||||
#define _TREZOR_T3W1_H
|
||||
|
||||
// settings for nrf52
|
||||
#define SPI_SCK_PIN 14
|
||||
#define SPI_MISO_PIN 15
|
||||
#define SPI_MOSI_PIN 16
|
||||
#define SPI_SS_PIN 13
|
||||
|
||||
#define RX_PIN_NUMBER 26
|
||||
#define TX_PIN_NUMBER 27
|
||||
#define CTS_PIN_NUMBER 6
|
||||
#define RTS_PIN_NUMBER 8
|
||||
|
||||
#define LED_ORANGE_PIN 22
|
||||
#define LED_GREEN_PIN 24
|
||||
#define BUTTON_USER_PIN 21
|
||||
|
||||
#define STAY_BLD_PIN 40
|
||||
#define GPIO_1_PIN 28
|
||||
#define GPIO_2_PIN 29
|
||||
#define GPIO_3_PIN 30
|
||||
|
||||
#endif //_TREZOR_T3W1_H
|
@ -0,0 +1,438 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include STM32_HAL_H
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#include "ble_hal.h"
|
||||
#include <string.h>
|
||||
#include "ble/int_comm_defs.h"
|
||||
#include "ble/messages.h"
|
||||
#include "ble/state.h"
|
||||
#include "buffers.h"
|
||||
#include "irq.h"
|
||||
#include "supervise.h"
|
||||
|
||||
#define SPI_QUEUE_SIZE 16
|
||||
|
||||
static UART_HandleTypeDef urt;
|
||||
|
||||
static SPI_HandleTypeDef spi = {0};
|
||||
static DMA_HandleTypeDef spi_dma = {0};
|
||||
|
||||
typedef struct {
|
||||
uint8_t buffer[BLE_PACKET_SIZE];
|
||||
bool used;
|
||||
bool ready;
|
||||
} spi_buffer_t;
|
||||
|
||||
BUFFER_SECTION spi_buffer_t spi_queue[SPI_QUEUE_SIZE];
|
||||
static int head = 0, tail = 0;
|
||||
static bool overrun = false;
|
||||
volatile uint16_t overrun_count = 0;
|
||||
volatile uint16_t msg_cntr = 0;
|
||||
volatile uint16_t first_overrun_at = 0;
|
||||
|
||||
static uint8_t int_comm_buffer[USB_DATA_SIZE];
|
||||
static uint16_t int_comm_msg_len = 0;
|
||||
static uint8_t int_event_buffer[USB_DATA_SIZE];
|
||||
static uint16_t int_event_msg_len = 0;
|
||||
|
||||
static bool g_comm_running = false;
|
||||
|
||||
void ble_comm_init(void) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
// synchronization signals
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_12;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_1_PIN;
|
||||
HAL_GPIO_Init(GPIO_1_PORT, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Alternate = 0;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_2_PIN;
|
||||
HAL_GPIO_Init(GPIO_2_PORT, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_3_PIN;
|
||||
HAL_GPIO_Init(GPIO_3_PORT, &GPIO_InitStructure);
|
||||
|
||||
__HAL_RCC_USART1_CLK_ENABLE();
|
||||
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF7_USART1;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
urt.Init.Mode = UART_MODE_TX_RX;
|
||||
urt.Init.BaudRate = 1000000;
|
||||
urt.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS;
|
||||
urt.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
urt.Init.Parity = UART_PARITY_NONE, urt.Init.StopBits = UART_STOPBITS_1;
|
||||
urt.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
urt.Instance = USART1;
|
||||
|
||||
HAL_UART_Init(&urt);
|
||||
|
||||
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||
__HAL_RCC_SPI1_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF5_SPI1;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_5;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
// GPIO_InitStructure.Pin = GPIO_PIN_9;
|
||||
// HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
spi_dma.Init.Channel = DMA_CHANNEL_3;
|
||||
spi_dma.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
spi_dma.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
spi_dma.Init.MemInc = DMA_MINC_ENABLE;
|
||||
spi_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
spi_dma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
spi_dma.Init.Mode = DMA_NORMAL;
|
||||
spi_dma.Init.Priority = DMA_PRIORITY_LOW;
|
||||
spi_dma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
spi_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
spi_dma.Init.MemBurst = DMA_MBURST_SINGLE;
|
||||
spi_dma.Init.PeriphBurst = DMA_PBURST_SINGLE;
|
||||
spi_dma.Instance = DMA2_Stream0;
|
||||
HAL_DMA_Init(&spi_dma);
|
||||
|
||||
spi.Instance = SPI1;
|
||||
spi.Init.Mode = SPI_MODE_SLAVE;
|
||||
spi.Init.Direction = SPI_DIRECTION_2LINES; // rx only?
|
||||
spi.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
spi.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
spi.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
spi.Init.NSS = SPI_NSS_HARD_INPUT;
|
||||
spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
||||
spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
spi.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
spi.Init.CRCPolynomial = 0;
|
||||
spi.hdmarx = &spi_dma;
|
||||
|
||||
spi_dma.Parent = &spi;
|
||||
|
||||
HAL_SPI_Init(&spi);
|
||||
|
||||
set_initialized(false);
|
||||
|
||||
tail = 0;
|
||||
}
|
||||
|
||||
void ble_comm_start(void) {
|
||||
memset(spi_queue, 0, sizeof(spi_queue));
|
||||
head = 0, tail = 0;
|
||||
overrun = false;
|
||||
svc_enableIRQ(DMA2_Stream0_IRQn);
|
||||
HAL_SPI_Receive_DMA(&spi, spi_queue[0].buffer, BLE_PACKET_SIZE);
|
||||
spi_queue[0].used = true;
|
||||
g_comm_running = true;
|
||||
ble_signal_running();
|
||||
}
|
||||
|
||||
void ble_comm_stop(void) {
|
||||
ble_signal_off();
|
||||
g_comm_running = false;
|
||||
svc_disableIRQ(DMA2_Stream0_IRQn);
|
||||
HAL_SPI_Abort(&spi);
|
||||
memset(spi_queue, 0, sizeof(spi_queue));
|
||||
}
|
||||
|
||||
bool ble_comm_running(void) { return g_comm_running; }
|
||||
|
||||
void ble_comm_send(uint8_t *data, uint32_t len) {
|
||||
HAL_UART_Transmit(&urt, data, len, 30);
|
||||
}
|
||||
|
||||
uint32_t ble_comm_receive(uint8_t *data, uint32_t len) {
|
||||
if (urt.Instance->SR & USART_SR_RXNE) {
|
||||
HAL_StatusTypeDef result = HAL_UART_Receive(&urt, data, len, 30);
|
||||
|
||||
if (result == HAL_OK) {
|
||||
return len;
|
||||
} else {
|
||||
if (urt.RxXferCount == len) {
|
||||
return 0;
|
||||
}
|
||||
return len - urt.RxXferCount - 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ble_int_comm_send(uint8_t *data, uint32_t len, uint8_t message_type) {
|
||||
uint16_t msg_len = len + OVERHEAD_SIZE;
|
||||
uint8_t len_hi = msg_len >> 8;
|
||||
uint8_t len_lo = msg_len & 0xFF;
|
||||
uint8_t eom = EOM;
|
||||
|
||||
HAL_UART_Transmit(&urt, &message_type, 1, 1);
|
||||
HAL_UART_Transmit(&urt, &len_hi, 1, 1);
|
||||
HAL_UART_Transmit(&urt, &len_lo, 1, 1);
|
||||
|
||||
HAL_UART_Transmit(&urt, data, len, 10);
|
||||
HAL_UART_Transmit(&urt, &eom, 1, 1);
|
||||
}
|
||||
|
||||
void flush_line(void) {
|
||||
while (urt.Instance->SR & USART_SR_RXNE) {
|
||||
(void)urt.Instance->DR;
|
||||
}
|
||||
}
|
||||
|
||||
void ble_uart_receive(void) {
|
||||
if (urt.Instance->SR & USART_SR_RXNE) {
|
||||
uint8_t init_byte = 0;
|
||||
|
||||
HAL_UART_Receive(&urt, &init_byte, 1, 1);
|
||||
|
||||
if (init_byte == INTERNAL_EVENT || init_byte == INTERNAL_MESSAGE) {
|
||||
uint8_t len_hi = 0;
|
||||
uint8_t len_lo = 0;
|
||||
HAL_UART_Receive(&urt, &len_hi, 1, 1);
|
||||
HAL_UART_Receive(&urt, &len_lo, 1, 1);
|
||||
|
||||
uint16_t act_len = (len_hi << 8) | len_lo;
|
||||
|
||||
if (act_len > UART_PACKET_SIZE) {
|
||||
flush_line();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *data = NULL;
|
||||
uint16_t *len = NULL;
|
||||
if (init_byte == INTERNAL_EVENT) {
|
||||
data = int_event_buffer;
|
||||
len = &int_event_msg_len;
|
||||
} else if (init_byte == INTERNAL_MESSAGE) {
|
||||
data = int_comm_buffer;
|
||||
len = &int_comm_msg_len;
|
||||
} else {
|
||||
memset(data, 0, USB_DATA_SIZE);
|
||||
*len = 0;
|
||||
flush_line();
|
||||
return;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef result =
|
||||
HAL_UART_Receive(&urt, data, act_len - OVERHEAD_SIZE, 5);
|
||||
|
||||
if (result != HAL_OK) {
|
||||
memset(data, 0, USB_DATA_SIZE);
|
||||
*len = 0;
|
||||
flush_line();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t eom = 0;
|
||||
HAL_UART_Receive(&urt, &eom, 1, 1);
|
||||
|
||||
if (eom == EOM) {
|
||||
*len = act_len - OVERHEAD_SIZE;
|
||||
} else {
|
||||
memset(data, 0, USB_DATA_SIZE);
|
||||
*len = 0;
|
||||
flush_line();
|
||||
}
|
||||
} else {
|
||||
flush_line();
|
||||
}
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
void ble_event_poll() {
|
||||
ble_uart_receive();
|
||||
|
||||
if (int_event_msg_len > 0) {
|
||||
process_poll(int_event_buffer, int_event_msg_len);
|
||||
memset(int_event_buffer, 0, USB_DATA_SIZE);
|
||||
int_event_msg_len = 0;
|
||||
}
|
||||
|
||||
if (!ble_initialized() && !is_ble_dfu_mode() && ble_firmware_running()) {
|
||||
send_state_request();
|
||||
}
|
||||
}
|
||||
|
||||
bool ble_firmware_running(void) {
|
||||
return HAL_GPIO_ReadPin(GPIO_2_PORT, GPIO_2_PIN) != 0;
|
||||
}
|
||||
|
||||
uint32_t ble_int_event_receive(uint8_t *data, uint32_t len) {
|
||||
ble_uart_receive();
|
||||
if (int_event_msg_len > 0) {
|
||||
memcpy(data, int_event_buffer,
|
||||
int_event_msg_len > len ? len : int_event_msg_len);
|
||||
memset(int_event_buffer, 0, USB_DATA_SIZE);
|
||||
uint32_t res = int_event_msg_len;
|
||||
int_event_msg_len = 0;
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t ble_int_comm_receive(uint8_t *data, uint32_t len) {
|
||||
ble_uart_receive();
|
||||
if (int_comm_msg_len > 0) {
|
||||
memcpy(data, int_comm_buffer,
|
||||
int_comm_msg_len > len ? len : int_comm_msg_len);
|
||||
memset(int_comm_buffer, 0, USB_DATA_SIZE);
|
||||
uint32_t res = int_comm_msg_len;
|
||||
int_comm_msg_len = 0;
|
||||
uint8_t cmd = INTERNAL_CMD_ACK;
|
||||
ble_int_comm_send(&cmd, sizeof(cmd), INTERNAL_EVENT);
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool start_spi_dma(void) {
|
||||
int tmp_tail = (tail + 1) % SPI_QUEUE_SIZE;
|
||||
if (spi_queue[tmp_tail].used || spi_queue[tmp_tail].ready) {
|
||||
overrun = true;
|
||||
overrun_count++;
|
||||
if (first_overrun_at == 0) {
|
||||
first_overrun_at = msg_cntr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
spi_queue[tmp_tail].used = true;
|
||||
HAL_SPI_Receive_DMA(&spi, spi_queue[tmp_tail].buffer, BLE_PACKET_SIZE);
|
||||
|
||||
tail = tmp_tail;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DMA2_Stream0_IRQHandler(void) {
|
||||
IRQ_ENTER(DMA2_Stream0_IRQn);
|
||||
|
||||
HAL_DMA_IRQHandler(&spi_dma);
|
||||
|
||||
IRQ_EXIT(DMA2_Stream0_IRQn);
|
||||
}
|
||||
|
||||
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
spi_queue[tail].ready = true;
|
||||
msg_cntr++;
|
||||
start_spi_dma();
|
||||
}
|
||||
|
||||
uint32_t ble_ext_comm_receive(uint8_t *data, uint32_t len) {
|
||||
svc_disableIRQ(DMA2_Stream0_IRQn);
|
||||
if (spi_queue[head].ready) {
|
||||
uint8_t *buffer = (uint8_t *)spi_queue[head].buffer;
|
||||
memcpy(data, buffer, len > BLE_PACKET_SIZE ? BLE_PACKET_SIZE : len);
|
||||
|
||||
spi_queue[head].used = false;
|
||||
spi_queue[head].ready = false;
|
||||
head = (head + 1) % SPI_QUEUE_SIZE;
|
||||
|
||||
if (overrun && start_spi_dma()) {
|
||||
// overrun was before, need to restart the DMA
|
||||
overrun = false;
|
||||
}
|
||||
|
||||
if (data[0] != '?') {
|
||||
// bad packet, restart the DMA
|
||||
HAL_SPI_Abort(&spi);
|
||||
|
||||
memset(spi_queue, 0, sizeof(spi_queue));
|
||||
head = 0;
|
||||
tail = 0;
|
||||
overrun = false;
|
||||
HAL_SPI_Receive_DMA(&spi, spi_queue[0].buffer, BLE_PACKET_SIZE);
|
||||
spi_queue[0].used = true;
|
||||
// todo return error?
|
||||
svc_enableIRQ(DMA2_Stream0_IRQn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
svc_enableIRQ(DMA2_Stream0_IRQn);
|
||||
return len > BLE_PACKET_SIZE ? BLE_PACKET_SIZE : len;
|
||||
}
|
||||
|
||||
svc_enableIRQ(DMA2_Stream0_IRQn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ble_reset_to_bootloader(void) {
|
||||
uint32_t tick_start = 0;
|
||||
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
|
||||
|
||||
HAL_Delay(10);
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
|
||||
|
||||
tick_start = HAL_GetTick();
|
||||
|
||||
while (HAL_GPIO_ReadPin(GPIO_1_PORT, GPIO_1_PIN) == GPIO_PIN_RESET) {
|
||||
if (HAL_GetTick() - tick_start > 4000) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
|
||||
|
||||
HAL_Delay(1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ble_reset(void) {
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
|
||||
HAL_Delay(50);
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ble_signal_running(void) {
|
||||
HAL_GPIO_WritePin(GPIO_3_PORT, GPIO_3_PIN, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
void ble_signal_off(void) {
|
||||
HAL_GPIO_WritePin(GPIO_3_PORT, GPIO_3_PIN, GPIO_PIN_RESET);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void ble_comm_init(void);
|
||||
|
||||
void ble_comm_send(uint8_t *data, uint32_t len);
|
||||
uint32_t ble_comm_receive(uint8_t *data, uint32_t len);
|
||||
|
||||
void ble_int_comm_send(uint8_t *data, uint32_t len, uint8_t message_type);
|
||||
uint32_t ble_int_event_receive(uint8_t *data, uint32_t len);
|
||||
uint32_t ble_int_comm_receive(uint8_t *data, uint32_t len);
|
||||
uint32_t ble_ext_comm_receive(uint8_t *data, uint32_t len);
|
||||
|
||||
void ble_event_poll(void);
|
||||
|
||||
bool ble_firmware_running(void);
|
||||
|
||||
bool ble_reset_to_bootloader(void);
|
||||
bool ble_reset(void);
|
Loading…
Reference in new issue