/********************************************************************* * SEGGER Microcontroller GmbH & Co. KG * * The Embedded Experts * ********************************************************************** * * * (c) 1995 - 2017 SEGGER Microcontroller GmbH & Co. KG * * * * Internet: segger.com Support: support_embos@segger.com * * * ********************************************************************** * * * embOS * Real time operating system for microcontrollers * * * * Please note: * * * * Knowledge of this file may under no circumstances * * be used to write a similar product or a real-time * * operating system for in-house use. * * * * Thank you for your fairness ! * * * ********************************************************************** * * * OS version: 4.34.1 * * * ********************************************************************** ---------------------------------------------------------------------- File : JLINKMEM_Process.c Purpose : Data handler for ARM J-Link communication over memory Layout of communication area: +----------+ TOS - TX_SIZE - RX_SIZE - 6 | | | RX_BUF | | | +----------+ TOS - TX_SIZE - 6 | RX_CNT | +----------+ TOS - TX_SIZE - 5 | HOST_ACT | +----------+ TOS - TX_SIZE - 4 | TX_CNT | +----------+ TOS - TX_SIZE - 3 | | | TX_BUF | | | +----------+ TOS - 3 | TX_SIZE | +----------+ TOS - 2 | RX_SIZE | +----------+ TOS - 1 | PROT_ID | +----------+ TOS TOS Initial top of stack as defined by linker settings (top of CSTACK) PROT_ID Magic number indicating the start of communication area RX_SIZE Size of receiving buffer in bytes TX_SIZE Size of sending buffer in bytes TX_BUF Sending buffer TX_CNT Number of bytes in sending buffer HOST_ACT Set to oen by host to indicate it is still active RX_CNT Number of bytes in the receiving buffer RX_BUF Receiving buffer ---------------------------END-OF-HEADER------------------------------ */ #include "RTOS.h" #include "JLINKMEM.h" /********************************************************************* * * Defines, configurable * ********************************************************************** */ /********************************************************************* * * Sizes of receiving and sending buffer. * * NOTE: * Before you change any of these values make sure OS_Start() * reserves enough bytes for the communication area. */ #define RX_BUF_SIZE 8 #define TX_BUF_SIZE 18 /********************************************************************* * * Defines, non- configurable * ********************************************************************** */ #define U8 unsigned char #define U16 unsigned short #define U32 unsigned int #define MAGIC_NUM 0x52 /* Identifies the start of our communication area. */ #define PROT_ID (*(volatile U8 *)(_BaseAddr - 1)) /* Id of the protocol. Always set to MAGIC_NUM */ #define RX_SIZE (*(volatile U8 *)(_BaseAddr - 2)) /* Size of receiving buffer in bytes */ #define TX_SIZE (*(volatile U8 *)(_BaseAddr - 3)) /* Size of sending buffer in bytes */ #define TX_CNT (*(volatile U8 *)(_BaseAddr - TX_BUF_SIZE - 4)) /* Stores the number of bytes we send to host */ /* Set by host to a non-null value when it connects to target. * The target sets this to null when it detects a communication timeout. */ #define HOST_CON (*(volatile U8 *)(_BaseAddr - TX_BUF_SIZE - 5)) #define RX_CNT (*(volatile U8 *)(_BaseAddr - TX_BUF_SIZE - 6)) /* Stores the number of bytes the host sent to us */ #define TX_TIMEOUT 1000 /* Time to wait for host to fetch the data from sending buffer (in ms) */ #define VTOR_ADDR (*(volatile OS_U32*) (0xE000ED08)) /* Vector table base register address */ /********************************************************************* * * Static data * ********************************************************************** */ /* Pointer to user callbacks */ void (* _pfOnRx) (U8 Data); void (* _pfOnTx) (void); OS_INT (* _pfGetNextChar) (void); static U32 _BaseAddr; static int _TxIsPending; /* Set when there is a character waiting to be sent */ static U8 _TxPendingData; /* Holds tha character waiting to be sent */ static int _IsInited; /* Set when the communication is initialised */ static U8* _pRxBuf; /* Start of receiving buffer */ static U8* _pTxBuf; /* Start of sending buffer */ /* Supervises the connection to host */ static int _TxTimeout; /* Set when the host fails to fetch our data */ static int _TxTimeoutTimer; static int _TxBufLocked; /* Serialises the access to our sending buffer */ /********************************************************************* * * Static code * ********************************************************************** */ /********************************************************************* * * _RetriggerTimer * * Function description */ static void _RetriggerTimer(void) { _TxTimeoutTimer = TX_TIMEOUT; } /********************************************************************* * * _HandleTxTimeout * * Function description * Sets the connection to host to inactive when the host fails to * fetch the data we send to it. Called when the send timeout * expires. */ static void _StopTimer(void) { _TxTimeoutTimer = 0; } /********************************************************************* * * _Init * * Function description * Performs initalisation of memory locations used for communication. */ static void _Init(void) { OS_U32 VectorTableBaseAddr; /* On Cortex-M initial top of stack is stored at address defined by VTOR */ VectorTableBaseAddr = VTOR_ADDR; VectorTableBaseAddr &= ~(0x3FuL); // Mask b6..b0 as those might not be zero ARM DDI 0403D chapter B3.2.5 page B3-716 _BaseAddr = (*(OS_U32*)VectorTableBaseAddr); HOST_CON = 0; RX_SIZE = RX_BUF_SIZE; TX_SIZE = TX_BUF_SIZE; RX_CNT = 0; TX_CNT = 0; PROT_ID = MAGIC_NUM; _pTxBuf = (U8 *)(_BaseAddr - TX_BUF_SIZE - 3); _pRxBuf = (U8 *)(_BaseAddr - TX_BUF_SIZE - RX_BUF_SIZE - 6); _TxIsPending = 0; } /********************************************************************* * * _LockTxBuf * * Function description * Gains exclusive access to sending buffer. * * Return value * 1 Sending buffer locked * 0 Sending buffer couldn't be locked as already in use. */ static int _LockTxBuf(void) { int Locked = 0; OS_DI(); if (!_TxBufLocked) { _TxBufLocked = 1; Locked = 1; } OS_RestoreI(); return Locked; } /********************************************************************* * * _UnlockTxBuf * * Function description * Releases the exclusive access to sending buffer. */ static void _UnlockTxBuf(void) { _TxBufLocked = 0; } /********************************************************************* * * _Receive * * Function description * Performs Command / data read from host */ static void _Receive(void) { int i; U8 *pBuf; if (RX_CNT > 0) { /* Data received ? */ if (_pfOnRx != NULL) { pBuf = _pRxBuf + (RX_BUF_SIZE - RX_CNT); for (i = 0; i < RX_CNT; ++i) { _pfOnRx(*pBuf); ++pBuf; } } RX_CNT = 0; } } /********************************************************************* * * _FillTxBuf * * Function description * Stores bytes in the sending buffer. */ static void _FillTxBuf(U8 Data) { int Cnt = 0; OS_INT Byte; U8 *pBuf; pBuf = _pTxBuf; *pBuf = Data; ++pBuf; ++Cnt; if (_pfGetNextChar != NULL) { /* Get more bytes from the communication state machine * until the sending buffer is full. */ while (1) { if (Cnt >= TX_BUF_SIZE) { break; } Byte = _pfGetNextChar(); if (Byte < 0) { break; } *pBuf = (U8)Byte; ++pBuf; ++Cnt; } } OS_DI(); _RetriggerTimer(); TX_CNT = (U8)Cnt; OS_RestoreI(); } /********************************************************************* * * _DropTxData * * Function description * Empties the sending buffer of embOS. */ static void _DropTxData(void) { if (_pfGetNextChar != NULL) { while (_pfGetNextChar() >= 0) { ; } } } /********************************************************************* * * _Send * * Function description * Sends data back to host if embOSView is ready to receive data. */ static void _Send(void) { if (TX_CNT == 0) { /* Can we send data? */ _StopTimer(); if (_TxIsPending) { _FillTxBuf(_TxPendingData); _TxIsPending = 0; } else { if (_pfOnTx != NULL) { if (_LockTxBuf()) { _pfOnTx(); _UnlockTxBuf(); } } } } } /********************************************************************* * * Public code * ********************************************************************** */ /********************************************************************* * * JLINKMEM_Process * * Function description * This function should be called more or less regularily to allow * memory reads while the application progam is running. * The more often it is called, the higher the transfer speed. */ void JLINKMEM_Process(void) { if (OS_IsRunning()) { /* No communication until the embOS starts */ if (!_IsInited) { _Init(); _IsInited = 1; } if (HOST_CON) { /* Do nothing until the host connects to us */ // // Handle Timeout timer // if (_TxTimeoutTimer != 0) { _TxTimeoutTimer--; if (_TxTimeoutTimer == 0) { _TxTimeout = 1; } } if (_TxTimeout) { HOST_CON = 0; _TxTimeout = 0; _TxIsPending = 0; _DropTxData(); RX_CNT = 0; /* Drop all bytes form receiving buffer. */ } else { _Receive(); _Send(); } } } } /********************************************************************* * * JLINKMEM_SendChar * * Function description * Send data to the host. This function is non-blocking. * If data can not be send it is stored in a buffer * and sent later, when the handler is called. */ void JLINKMEM_SendChar(U8 Data) { if (OS_IsRunning()) { /* No communication until the embOS starts */ if (!_IsInited) { _Init(); _IsInited = 1; } if (HOST_CON) { /* Do nothing until embOSView connects to us */ if (TX_CNT == 0) { if (_LockTxBuf()) { _FillTxBuf(Data); _UnlockTxBuf(); } else { _TxIsPending = 1; _TxPendingData = Data; } } else { _TxIsPending = 1; _TxPendingData = Data; } } else { // // Host not connected, drop characters // _DropTxData(); } } else { // // embOS not started, drop characters // _DropTxData(); } } /********************************************************************* * * JLINKMEM_SetpfOnRx */ void JLINKMEM_SetpfOnRx(void (* pf)(U8 Data)) { _pfOnRx = pf; } /********************************************************************* * * JLINKMEM_SetpfOnTx */ void JLINKMEM_SetpfOnTx(void (* pf)(void)) { _pfOnTx = pf; } /********************************************************************* * * JLINKMEM_SetpfGetNextChar */ void JLINKMEM_SetpfGetNextChar(OS_INT (* pf)(void)) { _pfGetNextChar = pf; } /*************************** end of file ****************************/