mirror of https://github.com/ARMmbed/mbed-os.git
Improve efficiency and formatting of ITM output
SerialWireOutput was outputting 1 character per 32-bit write to the ITM stimulus port. This is inefficient, and causes processing problems with some viewers due to them receiving 3 NUL bytes between each desired character. Rework to allow us to be more efficient, and eliminate those NUL bytes: * Retain existing mbed_itm_send() and clarify it's a single 32-bit write. * Add new mbed_itm_send_block() that is appropriate for sending character data, and modify SerialWireOutput to use it. * Move "wait for FIFO ready" check to before the write, rather than after. One minor correction - FIFOREADY is a single bit of the register read. Don't interpret reserved bits.pull/7518/head
parent
6cc1de13eb
commit
b110ef4c1c
|
@ -33,12 +33,8 @@ public:
|
||||||
|
|
||||||
virtual ssize_t write(const void *buffer, size_t size)
|
virtual ssize_t write(const void *buffer, size_t size)
|
||||||
{
|
{
|
||||||
const unsigned char *buf = static_cast<const unsigned char *>(buffer);
|
mbed_itm_send_block(ITM_PORT_SWO, buffer, size);
|
||||||
|
|
||||||
/* Send buffer one character at a time over the ITM SWO port */
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
mbed_itm_send(ITM_PORT_SWO, buf[i]);
|
|
||||||
}
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#if defined(DEVICE_ITM)
|
#if defined(DEVICE_ITM)
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -68,12 +69,26 @@ void mbed_itm_init(void);
|
||||||
* @brief Send data over ITM stimulus port.
|
* @brief Send data over ITM stimulus port.
|
||||||
*
|
*
|
||||||
* @param[in] port The stimulus port to send data over.
|
* @param[in] port The stimulus port to send data over.
|
||||||
* @param[in] data The data to send.
|
* @param[in] data The 32-bit data to send.
|
||||||
|
*
|
||||||
|
* The data is written as a single 32-bit write to the port.
|
||||||
*
|
*
|
||||||
* @return value of data sent.
|
* @return value of data sent.
|
||||||
*/
|
*/
|
||||||
uint32_t mbed_itm_send(uint32_t port, uint32_t data);
|
uint32_t mbed_itm_send(uint32_t port, uint32_t data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a block of data over ITM stimulus port.
|
||||||
|
*
|
||||||
|
* @param[in] port The stimulus port to send data over.
|
||||||
|
* @param[in] data The block of data to send.
|
||||||
|
* @param[in] len The number of bytes of data to send.
|
||||||
|
*
|
||||||
|
* The data is written using multiple appropriately-sized port accesses for
|
||||||
|
* efficient transfer.
|
||||||
|
*/
|
||||||
|
void mbed_itm_send_block(uint32_t port, const void *data, size_t len);
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifndef ITM_STIM_FIFOREADY_Msk
|
||||||
|
#define ITM_STIM_FIFOREADY_Msk 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ITM_ENABLE_WRITE 0xC5ACCE55
|
#define ITM_ENABLE_WRITE 0xC5ACCE55
|
||||||
|
|
||||||
#define SWO_NRZ 0x02
|
#define SWO_NRZ 0x02
|
||||||
|
@ -66,21 +70,64 @@ void mbed_itm_init(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void itm_out8(uint32_t port, uint8_t data)
|
||||||
|
{
|
||||||
|
/* Wait until port is available */
|
||||||
|
while ((ITM->PORT[port].u32 & ITM_STIM_FIFOREADY_Msk) == 0) {
|
||||||
|
__NOP();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write data to port */
|
||||||
|
ITM->PORT[port].u8 = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void itm_out32(uint32_t port, uint32_t data)
|
||||||
|
{
|
||||||
|
/* Wait until port is available */
|
||||||
|
while ((ITM->PORT[port].u32 & ITM_STIM_FIFOREADY_Msk) == 0) {
|
||||||
|
__NOP();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write data to port */
|
||||||
|
ITM->PORT[port].u32 = data;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t mbed_itm_send(uint32_t port, uint32_t data)
|
uint32_t mbed_itm_send(uint32_t port, uint32_t data)
|
||||||
{
|
{
|
||||||
/* Check if ITM and port is enabled */
|
/* Check if ITM and port is enabled */
|
||||||
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
|
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
|
||||||
((ITM->TER & (1UL << port)) != 0UL)) { /* ITM Port enabled */
|
((ITM->TER & (1UL << port)) != 0UL)) { /* ITM Port enabled */
|
||||||
/* write data to port */
|
itm_out32(port, data);
|
||||||
ITM->PORT[port].u32 = data;
|
|
||||||
|
|
||||||
/* Wait until data has been clocked out */
|
|
||||||
while (ITM->PORT[port].u32 == 0UL) {
|
|
||||||
__NOP();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mbed_itm_send_block(uint32_t port, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
const char *ptr = data;
|
||||||
|
|
||||||
|
/* Check if ITM and port is enabled */
|
||||||
|
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
|
||||||
|
((ITM->TER & (1UL << port)) != 0UL)) { /* ITM Port enabled */
|
||||||
|
/* Output single byte at a time until data is aligned */
|
||||||
|
while ((((uintptr_t) ptr) & 3) && len != 0) {
|
||||||
|
itm_out8(port, *ptr++);
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output bulk of data one word at a time */
|
||||||
|
while (len >= 4) {
|
||||||
|
itm_out32(port, *(const uint32_t *) ptr);
|
||||||
|
ptr += 4;
|
||||||
|
len -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output any trailing bytes */
|
||||||
|
while (len != 0) {
|
||||||
|
itm_out8(port, *ptr++);
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif // defined(DEVICE_ITM)
|
#endif // defined(DEVICE_ITM)
|
||||||
|
|
Loading…
Reference in New Issue