硬汉嵌入式论坛

 找回密码
 立即注册
查看: 474|回复: 3
收起左侧

[ThreadX全家桶] ZYNQ 7000 移植ThreadX后报DataAbort

[复制链接]
回帖奖励 9 个金币 回复本帖可获得 1 个金币奖励! 每人限 1 次

1

主题

3

回帖

6

积分

新手上路

积分
6
发表于 2023-8-8 17:43:45 | 显示全部楼层 |阅读模式
主频666MHz,系统时钟设置了100us,跑了一个主线程(未设时间片),和两个定时器线程(分别为100us和1ms触发一次)。移植在一个运动控制器中,运行后打开上位机软件可以正常连接和执行上位机命令,但是关闭上位机软件后就死机了,查看了debug窗口显示报data abort异常,触发异常的位置每次都不一样,共同点是提示是无法读取内存,摘抄了几个提供报错提示:
Size: 4 bytes, Type: struct TX_TIMER_INTERNAL_STRUCT *
Address: 0xea000014
Exception: Cannot read target memory. Memory read error at 0xEA000014. MMU section translation fault


Size: 4 bytes, Type: GLOBAL_STATUS (*)(struct Phoenix_ *,PACKET *)
Address: 0x7faa4
Exception: Cannot read target memory. Memory read error at 0x7FAA4. OCM is not enabled at 0x0007faa4. Invalid address



Size: 4 bytes, Type: int [16]
Address: 0xf800b6c3
Exception: Cannot read target memory. Memory read error at 0xF800B6C3. Invalid address 0xf800b6c3 - it can hang PS interconnect


查了几天没查出来什么问题,求各位大佬给点方向
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2023-8-8 18:28:15 | 显示全部楼层

回帖奖励 +1 个金币

现象不同,但反馈的问题都是目标内存访问失败,可以先仅创建一个任务试试,排除野指针和栈溢出。

然后这个是embOS的zynq的初始化配置,看看有没有mmu,cache之类的设置问题。

[C] 纯文本查看 复制代码
/*********************************************************************
*                     SEGGER Microcontroller GmbH                    *
*                        The Embedded Experts                        *
**********************************************************************
*                                                                    *
*       (c) 2003 - 2020  SEGGER Microcontroller GmbH                 *
*                                                                    *
*       [url=http://www.segger.com]www.segger.com[/url]     Support: [url=mailto:support@segger.com]support@segger.com[/url]               *
*                                                                    *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
Purpose : Initializes and handles the hardware for embOS
Literature:
  [1]  Generic Interrupt Controller (GIC-390) Errata Notice
       (\\fileserver\Techinfo\Company\ARM\GIC_GenericInterruptController\GIC_390_Errata_Notice_v6.pdf)
  [2]  Zynq-7000 All Programmable SoC Technical Reference Manual
       (\\fileserver\Techinfo\Company\Xilinx\Zynq_7000\ug585-Zynq-7000-TRM-v1.10.pdf)
*/

#include "RTOS.h"
#if defined(RTT) && RTT > 0
#include "SEGGER_SYSVIEW.h"
#else
  #define SEGGER_SYSVIEW_Conf()
#endif

#ifdef __ICCARM__
  #include <intrinsics.h>
#endif

#include "Zynq7007S.h"

/*********************************************************************
*
*       Configuration
*
**********************************************************************
*/
#define ALLOW_NESTED_INTERRUPTS  0   // Caution: Nesting interrupts will cause higher stack load on system stack CSTACK

#define DDR_DISABLE_WC           1   // Disable write combine of DDR controller
#define DDR_USE_INT_VREF         0   // Force DDR controller to use internal VREF

/*********************************************************************
*
*       Clock frequency settings (configuration)
*/
#ifndef   OS_FSYS                   /* CPU Main clock frequency     */
  #define OS_FSYS (666666687u)      /* Assume 666MHz                */
#endif

#ifndef   OS_PCLK_TIMER             /* Peripheral clock for timer   */
  #define OS_PCLK_TIMER (OS_FSYS/2) /* The private timer runs at 1/2 of CPU clock */
#endif

#ifndef   OS_PCLK_UART              /* Peripheral clock for UART    */
  #define OS_PCLK_UART (OS_FSYS/2)  /* May vary from CPU clock      */
#endif                              /* depending on CPU             */

#ifndef   OS_TICK_FREQ
  #define OS_TICK_FREQ  (1000u)
#endif

#define OS_TIMER_RELOAD ((OS_PCLK_TIMER / OS_TICK_FREQ) - 1u)

/*********************************************************************
*
*       Configuration of communication to embOSView
*/
#ifndef   OS_VIEW_IFSELECT
  #define OS_VIEW_IFSELECT  OS_VIEW_DISABLED
#endif

/*********************************************************************
*
*       UART settings for embOSView
*       If you do not want (or can not due to hardware limitations)
*       to dedicate a UART to embOSView, please define it to be -1
*       Currently no uart is supported.
*       When using DCC for communication, the UART is not used for embOSView,
*       regardless the OS_UART settings
*/
#if (OS_VIEW_IFSELECT == OS_VIEW_IF_UART)
  #ifndef   OS_UART
    #define OS_UART (-1)
  #endif

  #ifndef   OS_BAUDRATE
    #define OS_BAUDRATE (38400)
  #endif
#endif

/****** End of configurable options *********************************/

#if (OS_VIEW_IFSELECT == OS_VIEW_IF_JLINK)
  #include "JLINKDCC.h"
#endif

/********************************************************************/

#ifdef __ICCARM__
  #define OS_ARM_FUNC  __arm
  #define ATTRIBUTE_NAKED_NO_INLINE
#endif

#ifdef __GNUC__
  #define OS_ARM_FUNC
  #define ATTRIBUTE_NAKED_NO_INLINE __attribute__ ((naked, noinline))
  #pragma GCC diagnostic ignored "-Wunused-parameter" // Avoid warning for unused parameter with GCC
#endif

#ifdef __CC_ARM
  #define OS_ARM_FUNC
  #define OS_INTERWORK
  #define ATTRIBUTE_NAKED_NO_INLINE __attribute__ ((noinline))
#endif

/*********************************************************************
*
*       Memory layout
*/
#ifndef   OS_OCSRAM_IS_REMAPPED      /* Having the on-chip SRAM remapped, allows cached access to SRAM on address 0 */
  #define OS_OSCRAM_IS_REMAPPED (0)  /* Set to 1 when the bootloader remapped the SRAM to address 0x00 */
#endif

/*********************************************************************
*
*       Local defines (sfrs and addresses used in RTOSInit.c)
*
**********************************************************************
*/
#define SCU_BASE_ADDR                (0xF8F00000uL)

/* Private timer */
#define CORE_PRIV_TIMER_BASE_ADDR    (SCU_BASE_ADDR + 0x0600uL)
#define CORE_PRIV_TIMER_LOAD         (*(volatile unsigned int*) (CORE_PRIV_TIMER_BASE_ADDR + 0x00u))
#define CORE_PRIV_TIMER_COUNT        (*(volatile unsigned int*) (CORE_PRIV_TIMER_BASE_ADDR + 0x04u))
#define CORE_PRIV_TIMER_CONTROL      (*(volatile unsigned int*) (CORE_PRIV_TIMER_BASE_ADDR + 0x08u))
#define CORE_PRIV_TIMER_STATUS       (*(volatile unsigned int*) (CORE_PRIV_TIMER_BASE_ADDR + 0x0Cu))
#define CORE_PRIV_TIMER_INT_ID       (29u)

/* Interrupt controller GIC */
#define GIC_BASE_ADDR                (0xF8F00000u)
#define GICD_BASE_ADDR               (GIC_BASE_ADDR + 0x1000u)
#define GICC_BASE_ADDR               (GIC_BASE_ADDR + 0x0100u)
#define GICC_HPPIR                   (*(volatile unsigned int*) (GICC_BASE_ADDR + 0x018u))  // Highest Priority Pending Interrupt Register
#define GICD_IPRIORITY               (*(volatile unsigned int*) (GICD_BASE_ADDR + 0x400u))  // Interrupt Priority Registers

#define NUM_INT_SOURCES              (96u)  // The Zynq 7000 provides 96 interrupt sources

/* L2 cache */
#define L2CACHE_BASE_ADDR            (0xF8F02000u)

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
extern const OS_ARM_L2CACHE_API OS_L2CACHE_PL310;

extern unsigned int _vectors;  // Start of vector table, defined in startup file

/*********************************************************************
*
*       MMU and cache configuration
*
*  Notes
*    The translation table has to be aligned on 16384 bytes boundary
*    The translation table has to be located in un-initialized memory,
*    because it may be filled from startup, before segments and variables
*    are initialized.
*/
#ifdef __ICCARM__
  #pragma data_alignment=16384
  static __no_init OS_U32 _TranslationTable [0x1000];
#elif defined __CC_ARM
  #pragma arm section zidata = "NO_INIT"         //   Has to be declared as separate section UNINIT in the scatter file
  __align(16384) static OS_U32 _TranslationTable[0x1000];
  #pragma arm section zidata // back to default (.bss section)
#elif defined __GNUC__
  static OS_U32 _TranslationTable[0x1000] __attribute__ ((aligned (16384), section (".non_init")));
#endif

/*********************************************************************
*
*       Interrupt vector table
*
*  Notes
*    The translation table has to be located in un-initialized memory,
*    because it may be filled from startup, before segments and variables
*    are initialized.
*/
#ifdef __ICCARM__
  #pragma data_alignment=4
  static __no_init OS_ISR_HANDLER * _apIsrHandler[NUM_INT_SOURCES];
#elif defined __CC_ARM
  #pragma arm section zidata = "NO_INIT"         //   Has to be declared as separate section UNINIT in the scatter file
  __align(4) static OS_ISR_HANDLER * _apIsrHandler[NUM_INT_SOURCES];
  #pragma arm section zidata // back to default (.bss section)
#elif defined __GNUC__
  static OS_ISR_HANDLER * _apIsrHandler[NUM_INT_SOURCES] __attribute__ ((aligned (4), section (".no_init")));
#endif

/*********************************************************************
*
*       Local functions
*
**********************************************************************
*/

/*********************************************************************
*
*       _OS_ISR_Undefined()
*
*  Function description
*    Is called when an uninstalled interrupt was detected
*    As interrupt pending condition of peripherals has to be reset,
*    program will not continue when interrupt is ignored.
*/
static void _OS_ISR_Undefined(void);
static void _OS_ISR_Undefined(void) {
  volatile int Dummy;
  Dummy = 1;
  /* You may set a breakpoint here to detect uninstalled ISR-handler */
  while (Dummy > 0) {
  }
}

/*********************************************************************
*
*       _SpuriousIrqHandler()
*
*  Function description
*    A dummy spurious IRQ handler
*/
static OS_U32 _SpuriousIrqCnt;
static void _SpuriousIrqHandler(void) {
  _SpuriousIrqCnt++;
}

/*********************************************************************
*
*       OS_ISR_Tick()
*
*  Function description
*    The OS system timer interrupt
*/
static void OS_ISR_Tick (void);
static void OS_ISR_Tick (void) {
  CORE_PRIV_TIMER_STATUS = (1u << 0);  // Clear timer interrupt pending flag
  OS_TICK_Handle();
  #if ((defined(__ICCARM__) && OS_DEBUG) || (OS_VIEW_IFSELECT == OS_VIEW_IF_JLINK))
    JLINKDCC_Process();
  #endif
}

/*********************************************************************
*
*       _GIC_Init()
*
*  Function description
*    Initialize interrupt controller by setting default vectors
*    and clearing all interrupts
*/
static void _GIC_Init(void) {
  OS_U32 i;
  //
  // Set GIC base address
  //
  OS_GIC_SetCPUInterfaceBaseAddr(GIC_BASE_ADDR + 0x0100);
  OS_GIC_SetDistributionBaseAddr(GIC_BASE_ADDR + 0x1000);
  //
  // Configure all interrupts
  //
  for (i = 0; i < NUM_INT_SOURCES; i++) {
    _apIsrHandler[i] = _OS_ISR_Undefined;  // Set default interrupt handler

    OS_GIC_SetIntSecure(i);                // Set to secure
    OS_GIC_DisableInt(i);                  // Disable interrupts
    //
    // Initialize all Interrupt pointer target register to address the first A9 core
    // The first 8 registers are fixed
    //
    if (i > 8u) {
      OS_GIC_SetTargetProc(i, 0x01);
    }
  }
  //
  // Configure priority mask to lowest value (highest number) - enables all priorities
  //
  OS_GIC_SetPrioThreshold(0xFF);
  //
  // This register defines the point at which the priority value fields split into two parts,
  // the group priority field and the subpriority field.
  //
  OS_GIC_SetPrioGroup(0x00);
  //
  // Enable the GIC
  //
  OS_GIC_Enable();
}

/*********************************************************************
*
*       _OS_GetHWTimerCycles()
*
*  Function description
*    Returns the current hardware timer count value
*
*  Return value
*    Current timer count value
*/
static unsigned int _OS_GetHWTimerCycles(void) {
  return CORE_PRIV_TIMER_COUNT;
}

/*********************************************************************
*
*       _OS_GetHWTimer_IntPending()
*
*  Function description
*    Returns if the hardware timer interrupt pending flag is set
*
*  Return value
*    == 0; Interrupt pending flag not set
*    != 0: Interrupt pending flag set
*/
static unsigned int _OS_GetHWTimer_IntPending(void) {
  return CORE_PRIV_TIMER_STATUS & (1u << 0);
}

/*********************************************************************
*
*       Global functions
*
**********************************************************************
*/

/*********************************************************************
*
*       OS_InitHW()
*
*  Function description
*    Initialize the hardware (timer) required for embOS to run.
*    May be modified, if an other timer should be used.
*/
const OS_SYSTIMER_CONFIG SysTimerConfig = {OS_PCLK_TIMER, OS_TICK_FREQ, 0u, _OS_GetHWTimerCycles, _OS_GetHWTimer_IntPending};

void OS_InitHW(void) {
  OS_U32 TickPrio;

  OS_INT_IncDI();
  OS_ARM_CACHE_Sync();  // Ensure, caches are synchronized
  //
  // Set vector table base address
  //
  OS_ARM_SetVBAR((OS_U32)&_vectors);
  //
  // Initialize GIC
  //
  _GIC_Init();
  //
  // Install OS timer ISR Handler and set interrupt priority to lowest priority
  //
  OS_ARM_InstallISRHandler(CORE_PRIV_TIMER_INT_ID, OS_ISR_Tick);
  OS_ARM_ISRSetPrio(CORE_PRIV_TIMER_INT_ID, 0xFFu);              // Set to lowest level, ALL BITS set
  TickPrio  = OS_ARM_ISRSetPrio(CORE_PRIV_TIMER_INT_ID, 0xFFu);  // Read back priority to examine relevant preemption-level-bits
  TickPrio -= 1;                                                 // Set to low preemption level, 1 level higher than lowest
  OS_ARM_ISRSetPrio(CORE_PRIV_TIMER_INT_ID, TickPrio);
  OS_ARM_EnableISR(CORE_PRIV_TIMER_INT_ID);
  //
  // Initialize private Timer as embOS system timer, enable timer and timer interrupt
  //
  CORE_PRIV_TIMER_CONTROL = 0x00u;            // Stop Timer, set Prescaler to 1
  CORE_PRIV_TIMER_LOAD    = OS_TIMER_RELOAD;  // Set timer interval
  CORE_PRIV_TIMER_CONTROL = (1u << 0)         // Enable Timer
                          | (1u << 1)         // Set auto reload mode
                          | (1u << 2);        // Enable timer interrupt
  //
  // Setup values for usec precise system time functions
  //
  OS_TIME_ConfigSysTimer(&SysTimerConfig);
  //
  // Configure and initialize SEGGER SystemView
  //
#if (OS_PROFILE != 0)
  SEGGER_SYSVIEW_Conf();
#endif
  //
  // Initialize the optional communication for embOSView
  //
#if (OS_VIEW_IFSELECT != OS_VIEW_DISABLED)
  OS_COM_Init();
#endif
  OS_INT_DecRI();
}

/*********************************************************************
*
*       OS_Idle()
*
*  Function description
*    This is basically the "core" of the idle loop.
*    This core loop can be changed, but:
*    The idle loop does not have a stack of its own, therefore no
*    functionality should be implemented that relies on the stack
*    to be preserved. However, a simple program loop can be programmed
*    (like toggling an output or incrementing a counter)
*/
void OS_Idle(void) {    // Idle loop: No task is ready to execute
  while (1) {           // Nothing to do ... wait for interrupt
    #if ((OS_VIEW_IFSELECT != OS_VIEW_IF_JLINK) && (OS_DEBUG == 0))
      #if ((defined __ICCARM__) && (__VER__ < 6300000))
        __asm(" wfi");
      #else
//        __asm volatile(" wfi");
      #endif
    #endif
  }
}

/*********************************************************************
*
*       OS_GetTime_Cycles()
*
*  Function description
*    This routine is required for task-info via embOSView or high
*    resolution time measurement functions.
*    It returns the system time in timer clock cycles.
*/
OS_U32 OS_GetTime_Cycles(void) {
  OS_U32 Time;
  OS_U32 Cnt;

  Time = OS_TIME_GetTicks32();
  Cnt  = OS_TIMER_RELOAD - CORE_PRIV_TIMER_COUNT;
  //
  // Check if timer interrupt pending ...
  //
  if ((CORE_PRIV_TIMER_STATUS & (1u << 0)) != 0u) {
    Cnt = OS_TIMER_RELOAD - CORE_PRIV_TIMER_COUNT;  // Interrupt pending, re-read timer and adjust result
    Time++;
  }
  return (OS_TIMER_RELOAD * Time) + Cnt;
}

/*********************************************************************
*
*       OS_ConvertCycles2us()
*
*  Function description
*    Convert Cycles into micro seconds.
*
*    If your clock frequency is not a multiple of 1 MHz,
*    you may have to modify this routine in order to get proper
*    diagnostics.
*
*    This routine is required for profiling or high resolution time
*    measurement only. It does not affect operation of the OS.
*/
OS_U32 OS_ConvertCycles2us(OS_U32 Cycles) {
#if (OS_PCLK_TIMER / 1000000 * 1000000 == OS_PCLK_TIMER)
  return (Cycles / (OS_PCLK_TIMER / 1000000));
#else
  long long t;
  t  = Cycles;
  t *= 1000000;
  t /= OS_PCLK_TIMER;
  return (OS_U32)t;
#endif
}

/*********************************************************************
*
*       Optional communication with embOSView
*
**********************************************************************
*/
#if (OS_VIEW_IFSELECT == OS_VIEW_IF_JLINK)

/*********************************************************************
*
*       _DCC_OnRx()
*/
static void _DCC_OnRx(unsigned Channel, OS_U8 Data) {
  OS_USE_PARA(Channel);  // Not supported by this version, suppress warning
  OS_COM_OnRx(Data);
}

/*********************************************************************
*
*       _DCC_OnTx()
*/
static void _DCC_OnTx(unsigned Channel) {
  OS_USE_PARA(Channel);  // Not supported by this version, suppress warning
  OS_COM_OnTx();
}

/*********************************************************************
*
*       OS_COM_Init()
*
*  Function description
*    Initialize DCC for embOSView
*/
void OS_COM_Init(void) {
  JLINKDCC_SetpfOnRx(1, _DCC_OnRx);
  JLINKDCC_SetpfOnTx(1, _DCC_OnTx);
}

/*********************************************************************
*
*       OS_COM_Send1()
*
*  Function description
*    Send 1 character via DCC
*/
void OS_COM_Send1(OS_U8 c) {
  JLINKDCC_SendCharOnChannelNB(1, c);
}

#elif (OS_VIEW_IFSELECT == OS_VIEW_DISABLED)

/*********************************************************************
*
*       OS_COM_Send1()
*
*  Function description
*    Dummy routine.
*/
void OS_COM_Send1(OS_U8 c) {
  OS_USE_PARA(c);           // Avoid compiler warning
  OS_COM_ClearTxActive();  // Let embOS know that Tx is not busy
}

#else
  #error "Selected embOSView interface is currently not supported."
#endif

/*********************************************************************
*
*       OS interrupt handler and ISR specific functions
*
**********************************************************************
*/

/*********************************************************************
*
*       OS_irq_handler()
*
*  Function description
*    Detect reason for IRQ and call corresponding service routine.
*    OS_irq_handler is called from the IRQ_handler function
*    found in RTOS.s.
*    IRQ_Handler has to be inserted in the vector table in the
*    startup code.
*/
extern unsigned int SEGGER_SYSVIEW_TickCnt;
extern unsigned int SEGGER_SYSVIEW_InterruptId;

OS_INTERWORK void OS_irq_handler(void) {
  OS_ISR_HANDLER  *pISR;
  volatile OS_U32 Dummy;
  OS_U32          int_id;
  OS_U32          icdipr0_value;

  Dummy  = GICC_HPPIR;       // Erratum 801120 [1] - ensure subsequent ICCIAR data will be correct
  OS_USE_PARA(Dummy);        // Avoid compiler warning about set but unused variable
  int_id = OS_GIC_AckInt();  // Acknowledge the interrupt and read the interrupt ID
  //
  // Save the interrupt id for SEGGER_SYSVIEW_X_GetInterruptId()
  //
#if (OS_PROFILE != 0) && (defined(RTT) && RTT > 0)
  SEGGER_SYSVIEW_InterruptId = int_id;
#endif
  //
  // Read data of 0x0 (SGI ID0 from CPU0) is possibly affected by 733075
  // Interrupt IDs 0x3FE and 0x3FF are also possibly affected
  //
  if ((int_id == 0u) || (int_id  >= 0x3FEu)) {
    //
    // Erratum 733075 - prevent possible CPU interface deadlock (ARM Errata Notice, PR258-GENC-008719 v6.0).
    // Assumes SGI ID0 from CPU0 is not used as suggested by ARM.
    //
    icdipr0_value  = GICD_IPRIORITY; // One way to get the value for the workaround write is to read it first
    GICD_IPRIORITY = icdipr0_value;
#if ((defined __ICCARM__) && (__VER__ < 6300000))
    __asm("dsb");                   // Ensure write completes before any future ICCHPIR or ICCIAR reads
#else
    __asm volatile("dsb");
#endif
  }

  if ((int_id == 0x3FEu) || (int_id == 0x3FFu)) {  // Check for spurious interrupts
     _SpuriousIrqHandler();
  } else {
    if (int_id < NUM_INT_SOURCES) {
      pISR = _apIsrHandler[int_id]; // Get interrupt vector handler
      #if (OS_PROFILE != 0) && (defined(RTT) && RTT > 0)
      if (int_id == CORE_PRIV_TIMER_INT_ID) {
        SEGGER_SYSVIEW_TickCnt++;
      }
      #endif
      #if ALLOW_NESTED_INTERRUPTS
      OS_INT_EnterNestable();       // Now interrupts may be reenabled. If nesting should be allowed
      #else
      OS_INT_Enter();               // Inform OS that interrupt handler is running
      #endif
      //
      // Call interrupt service routine
      //
      pISR();
      #if ALLOW_NESTED_INTERRUPTS
      OS_INT_LeaveNestable();       // Leave nestable interrupt, perform task switch if required
      #else
      OS_INT_Leave();               // Leave interrupt, perform task switch if required
      #endif
    }
    OS_GIC_EOI(int_id);             // End interrupt
  }
}

/*********************************************************************
*
*       OS_ARM_InstallISRHandler()
*
*  Function description
*    Installs an interrupt handler
*
*  Parameters
*    ISRIndex:    ISR index
*    pISRHandler: Interrupt handler function address
*/
OS_ISR_HANDLER* OS_ARM_InstallISRHandler (int ISRIndex, OS_ISR_HANDLER* pISRHandler) {
  OS_ISR_HANDLER *pOldHandler;

#if (OS_DEBUG != 0)
  if ((unsigned int)ISRIndex >= NUM_INT_SOURCES) {
    OS_Error(OS_ERR_ISR_INDEX);
  }
#endif
  OS_INT_Disable();
  pOldHandler             = _apIsrHandler[ISRIndex];
  _apIsrHandler[ISRIndex] = pISRHandler;
  OS_INT_EnableConditional();
  return pOldHandler;
}

/*********************************************************************
*
*       OS_ARM_EnableISR()
*
*  Function description
*    Enables an interrupt
*
*  Parameters
*    ISRIndex: ISR index
*/
void OS_ARM_EnableISR(int ISRIndex) {
#if (OS_DEBUG != 0)
  if ((unsigned)ISRIndex >= NUM_INT_SOURCES) {
    OS_Error(OS_ERR_ISR_INDEX);
  }
#endif
  OS_INT_Disable();
  OS_GIC_EnableInt(ISRIndex);
  OS_INT_EnableConditional();
}

/*********************************************************************
*
*       OS_ARM_DisableISR()
*
*  Function description
*    Disables an interrupt
*
*  Parameters
*    ISRIndex: ISR index
*/
void OS_ARM_DisableISR(int ISRIndex) {
#if (OS_DEBUG != 0)
  if ((unsigned)ISRIndex >= NUM_INT_SOURCES) {
    OS_Error(OS_ERR_ISR_INDEX);
  }
#endif
  OS_INT_Disable();
  OS_GIC_DisableInt(ISRIndex);
  OS_INT_EnableConditional();
}

/*********************************************************************
*
*       OS_ARM_ISRSetPrio()
*
*  Function description
*    Sets an interrupt priority
*
*  Parameters
*    ISRIndex: ISR index
*    Prio    : ISR priority
*/
int OS_ARM_ISRSetPrio(int ISRIndex, int Prio) {
  OS_U32  OldPrio;
#if (OS_DEBUG != 0)
  if ((unsigned)ISRIndex >= NUM_INT_SOURCES) {
    OS_Error(OS_ERR_ISR_INDEX);
  }
#endif
  OS_INT_Disable();
  OldPrio = OS_GIC_SetPrio(ISRIndex, Prio);
  OS_INT_EnableConditional();
  return (int)OldPrio;
}

/*********************************************************************
*
*       OS_ARM_ClearPendingFlag()
*
*  Function description
*    Clears an interrupt pending flag
*
*  Parameters
*    ISRIndex: ISR index
*/
void OS_ARM_ClearPendingFlag(int ISRIndex) {
#if (OS_DEBUG != 0)
  if ((unsigned int)ISRIndex >= NUM_INT_SOURCES) {
    OS_Error(OS_ERR_ISR_INDEX);
  }
#endif
  OS_INT_Disable();
  OS_GIC_ClrPending(ISRIndex);
  OS_INT_EnableConditional();
}

/*********************************************************************
*
*       OS_ARM_IsPending()
*
*  Function description
*    Checks if an interrupt is pending
*
*  Parameters
*    ISRIndex: ISR index
*
*  Return value
*    0: Interrupt is not pending
*    1: Interrupt is pending
*/
unsigned int OS_ARM_IsPending(int ISRIndex) {
  OS_U32 Result;

#if (OS_DEBUG != 0)
  if ((unsigned int)ISRIndex >= NUM_INT_SOURCES) {
    OS_Error(OS_ERR_ISR_INDEX);
  }
#endif
  OS_INT_Disable();
  Result = OS_GIC_IsPending(ISRIndex);
  OS_INT_EnableConditional();
  return Result;
}

/*********************************************************************
*
*       _InitQSPI()
*
*  Function description
*    Perform initialization of QSPI controller
*/
__attribute__ ((section (".init")))
static void _InitQSPI(void) {
  REG_SLCR_UNLOCK = SCLR_UNLOCK_KEY;
  REG_SLCR_APER_CLK_CTRL |= (0x00000001 << 23); // LQSPI_CPU_1XCLKACT: 1 == Enable clock for QSPI controller
  REG_SLCR_LQSPI_CLK_CTRL = 0
                          | (0x00000001 << 0)   // CLKACT: 1 == Clock enabled
                          | (0x00000000 << 4)   // SRCSEL: 0 == IO_PLL, 2 == ARM_PLL, 3 == DDR_PLL
                          | (0x00000005 << 8)   // DIVISOR: Controller clock == SRCSEL / DIVISOR
                          ;
  //
  // Init PIOs needed for QSPI operation after controller init is done
  //
  REG_SLCR_APER_CLK_CTRL |= (1 << 22); // GPIO_CPU_1XCLKACT: 1 == Enable for GPIO controller
  REG_SLCR_MIO_PIN_01 = MIO_PIN_OPT_IO_CMOS_3V3  | MIO_PIN_OPT_ENA_SPEED_FAST | MIO_PIN_OPT_LVL01_MUX;  // MIO_PIN_01: QSPI_#CS
  REG_SLCR_MIO_PIN_02 = MIO_PIN_OPT_IO_CMOS_3V3  | MIO_PIN_OPT_ENA_SPEED_FAST | MIO_PIN_OPT_LVL01_MUX;  // MIO_PIN_02: QSPI_IO0
  REG_SLCR_MIO_PIN_03 = MIO_PIN_OPT_IO_CMOS_3V3  | MIO_PIN_OPT_ENA_SPEED_FAST | MIO_PIN_OPT_LVL01_MUX;  // MIO_PIN_03: QSPI_IO1
  REG_SLCR_MIO_PIN_04 = MIO_PIN_OPT_IO_CMOS_3V3  | MIO_PIN_OPT_ENA_SPEED_FAST | MIO_PIN_OPT_LVL01_MUX;  // MIO_PIN_04: QSPI_IO2
  REG_SLCR_MIO_PIN_05 = MIO_PIN_OPT_IO_CMOS_3V3  | MIO_PIN_OPT_ENA_SPEED_FAST | MIO_PIN_OPT_LVL01_MUX;  // MIO_PIN_05: QSPI_IO3
  REG_SLCR_MIO_PIN_06 = MIO_PIN_OPT_IO_CMOS_3V3  | MIO_PIN_OPT_ENA_SPEED_FAST | MIO_PIN_OPT_LVL01_MUX;  // MIO_PIN_06: QSPI_CLK
  REG_SLCR_MIO_PIN_08 = MIO_PIN_OPT_IO_CMOS_3V3  | MIO_PIN_OPT_ENA_SPEED_FAST | MIO_PIN_OPT_LVL01_MUX;  // MIO_PIN_08: QSPI_FBCLK
  //
  // Init QSPI for memory mapped mode
  // We do not directly execute from flash but copy all stuff at boot time, so flash speed is only partially important
  // We only use single pin SPI mode, so we set SPI speed to 50 MHz so we can use the basic read commands that does not need dummy cycles (which may differ from flash to flash / vendor)
  //
//  REG_QSPIC_CONFIG_REG = 0
//                       | (1uL << 31) // leg_flsh: 1 == Memory mapped or I/O mode (not legacy SPI)
//                       | (0uL << 26) // endian: 0 == little endian access when reading/writing from/to Rx/Tx regs
//                       | (1uL << 19) // Holdb_dr: 1 == Holdb and WPn pins are actively driven by the qspi controller in 1-bit and 2-bit modes
//                       | (1uL << 17) // Reserved, must be 1
//                       | (0uL << 15) // Man_start_en: 0 == Auto mode, data + command is send as soon as Tx regs are accessed
//                       | (0uL << 14) // Manual_CS: 0 == Auto mode
//                       | (0uL << 10) // PCS: Controls state of nCS in case Manual_CS == 1
//                       | (0uL <<  8) // REF_CLK: Must be 0
//                       | (3uL <<  6) // FIFO_WIDTH: Must be 3 (32-bit)
//                       | (1uL <<  3) // BAUD_RATE_DIV: Baudrate = 2 ^ (BAUD_RATE_DIV + 1) => I/O PLL (200 MHz) is used as source clock for QSPI baudrate generation
//                       | (0uL <<  2) // CLK_PH: SCK is active between transfers
//                       | (0uL <<  1) // CLK_POL: 1 == SCK is HIGH between transfers
//                       | (1uL <<  0) // MODE_SEL: 1 == SPI is in master mode
//                       ;
  REG_QSPIC_CONFIG_REG = 0
                       | (1uL << 31) // leg_flsh: 1 == Memory mapped or I/O mode (not legacy SPI)
                       | (0uL << 26) // endian: 0 == little endian access when reading/writing from/to Rx/Tx regs
                       | (1uL << 19) // Holdb_dr: 1 == Holdb and WPn pins are actively driven by the qspi controller in 1-bit and 2-bit modes
                       | (1uL << 17) // Reserved, must be 1
                       | (0uL << 15) // Man_start_en: 0 == Auto mode, data + command is send as soon as Tx regs are accessed
                       | (0uL << 14) // Manual_CS: 0 == Auto mode
                       | (0uL << 10) // PCS: Controls state of nCS in case Manual_CS == 1
                       | (0uL <<  8) // REF_CLK: Must be 0
                       | (3uL <<  6) // FIFO_WIDTH: Must be 3 (32-bit)
                       | (0uL <<  3) // BAUD_RATE_DIV: Baudrate = 2 ^ (BAUD_RATE_DIV + 1) => I/O PLL (200 MHz) is used as source clock for QSPI baudrate generation
                       | (0uL <<  2) // CLK_PH: SCK is active between transfers
                       | (0uL <<  1) // CLK_POL: 1 == SCK is HIGH between transfers
                       | (1uL <<  0) // MODE_SEL: 1 == SPI is in master mode
                       ;
  //
  // Configure and enable linear QSPI mode (memory mapped mode)
  // Need to take care of the following before entering linear QSPI mode:
  // TXFIFO and RXFIFO are empty
  // REG_QSPIC_CR[Manual_CS] and REG_QSPIC_CR[PCS] must be 0
  //
//  REG_QSPIC_LQSPI_CFG = 0
//                     | (1uL << 31) // LQ_MODE: 1 == Linear quad SPI mode
//                     | (0uL << 30) // TWO_MEM: 1 == Lower and upper memories are active
//                     | (0uL << 29) // SEP_BUS: 1 == Separate memory bus for upper and lower memories
//                     | (0uL << 28) // U_PAGE: 1 == Select upper memory page as visible. Don't care if LQ_MODE == 0 AND TWO_MEM == 1 AND SEP_BUS == 0
//                     | (1uL << 26) // Reserved. Must be 1
//                     | (0uL << 25) // MODE_EN: Enable MODE_BITS[23:16] to be sent. Must be set for dual/quad mode. Must be clear for all other modes
//                     | (0uL << 24) // MODE_ON: 1 ==  instruction code is only sent for the very first read transfer
//                     | (0uL << 16) // MODE_BITS: If bit 25 is set, this value is required for both dual I/O read and quad I/O read. See vendor's datasheet for more information.
//                     | (0uL <<  8) // DUMMY_BYTE: Number of dummy bytes between address and return read data
//                     | (3uL <<  0) // INST_CODE: Read instruction code (0x03: Read, 0xEB: Fast read quad I/O)
//                     ;
  REG_QSPIC_LQSPI_CFG = 0
                     | (1uL << 31) // LQ_MODE: 1 == Linear quad SPI mode
                     | (0uL << 30) // TWO_MEM: 1 == Lower and upper memories are active
                     | (0uL << 29) // SEP_BUS: 1 == Separate memory bus for upper and lower memories
                     | (0uL << 28) // U_PAGE: 1 == Select upper memory page as visible. Don't care if LQ_MODE == 0 AND TWO_MEM == 1 AND SEP_BUS == 0
                     | (1uL << 26) // Reserved. Must be 1
                     | (0uL << 25) // MODE_EN: Enable MODE_BITS[23:16] to be sent. Must be set for dual/quad mode. Must be clear for all other modes
                     | (0uL << 24) // MODE_ON: 1 ==  instruction code is only sent for the very first read transfer
                     | (0x00uL << 16) // MODE_BITS: If bit 25 is set, this value is required for both dual I/O read and quad I/O read. See vendor's datasheet for more information.
                     | (1uL <<  8) // DUMMY_BYTE: Number of dummy bytes between address and return read data
                     | (0x3buL <<  0) // INST_CODE: Read instruction code (0x03: Read, 0xEB: Fast read quad I/O)
                     ;
  REG_QSPIC_TX_THRES_REG = 1; // Report Tx-FIFO full as soon as min. 1 byte is in the FIFO
  REG_QSPIC_RX_THRES_REG = 1; // Report Rx-FIFO full as soon as min. 1 byte is in the FIFO

  REG_QSPIC_LPBK_DLY_ADJ = 0
                         | (1uL << 5) // USE_LPBK: 1 == Use internal loopback master clock for read data capturing when baud rate divisor (reg 0x00) is 2
                         | (0 << 3)   // DLY1: Must be set to 0 if Loopback clk used
                         | (0 << 0)   // DLY0: Must be set to 0 if Loopback clk used
                         ;
  REG_QSPIC_EN_REG = 1;  // SPI_EN: Enable SPI
  REG_SLCR_LOCK = SCLR_LOCK_KEY;
}

/*********************************************************************
*
*       _InitPLLs()
*
*  Function description
*    Perform initialization of PLL
*/
__attribute__ ((section (".init")))
static void _InitPLLs(void) {
  OS_U32 v;
  //
  // Zynq-7000S maximum frequency: 766 MHz
  //
  // The Zynq-7000S provides 3 PLLs:
  //   ARM PLL => Can be used to feed the CPU and some peripherals
  //   DDR PLL => Exclusively for DDR RAM
  //   I/O PLL => Mainly used for I/O peripherals (can be used but does not have to...)
  // Clock tree:
  //   PS_CLK => ARM PLL (ARM_PLL_CTRL) => 6-bit div (ARM_CLK_CTRL[DIVISOR]) => CPU_1x, CPU_2x, CPU_3x2x, CPU_6x4x
  //   PS_CLK => DDR PLL (DDR_PLL_CTRL) => 6-bit div (DDR_CLK_CTRL[DDR_3XCLK_DIVISOR]) => DDR_3x
  //   PS_CLK => DDR PLL (DDR_PLL_CTRL) => 6-bit div (DDR_CLK_CTRL[DDR_2XCLK_DIVISOR]) => DDR_2x
  //   PS_CLK => IO PLL  (IO_PLL_CTRL)                                                 => I/Os
  //
  // Explanation:
  //   CPU_1x   == PLLOut / Div * 1/6
  //   CPU_2x   == (PLLOut / Div) * 2/6
  //   CPU_3x2x == (PLLOut / Div) * 2/6   or   (PLLOut / Div) * 3/6 in case CLK_621_TRUE [0] == 1
  //   CPU_6x4x == (PLLOut / Div) * 4/6   or   (PLLOut / Div) * 6/6 in case CLK_621_TRUE [0] == 1
  //
  // Configuration for the emPower Zynq:
  //   PS_CLK: 33.3 MHz (external oscillator)
  //   CLK_621_TRUE: 1 (Using 6:3:2:1)
  //   ARM PLLOut: 1333 MHz
  //
  REG_SLCR_UNLOCK = SCLR_UNLOCK_KEY;
  //
  // Init ARM PLL
  // We can change the register values with no risk as they only become active on a PLL reset
  //
  //
  // Small code exception here:
  // To make porting to macro file easier, we always write the value into temp variable v first
  //
  //
  // Values for ARM_PLL_CFG taken from the "PLL Frequency Control Settings" table 25-6 of the
  // Zynq 7000 Technical Reference Manual (TRM)
  //
  v = 0
    | (0x02 <<  4)  // PLL_RES
    | (0x02 <<  8)  // PLL_CP
    | (0xFA << 12)  // LOCK_CNT
    ;
  REG_SLCR_ARM_PLL_CFG = v;
  v = 0
    | (   0 <<  1)  // PLL_PWRDWN: 0 == PLL powered up
    | (   0 <<  3)  // PLL_BYPASS_QUAL: 0 == Bypass is controlled by PLL_BYPASS_FORCE
    | (   1 <<  4)  // PLL_BYPASS_FORCE: 1 == Bypass PLL
    | (0x28 << 12)  // PLL_FDIV: Multiplier for PLL
    ;
  REG_SLCR_ARM_PLL_CTRL = v;
  v = 0             // Set dividers before PLL gets active so we never get out of spec. with the clocks
    | (0x0  <<  4)  // SRCSEL: Use ARM PLL
    | (0x2  <<  8)  // DIVISOR
    | (0x1  << 24)  // CPU_6OR4XCLKACT: CPU_6x4x domain active
    | (0x1  << 25)  // CPU_3OR2XCLKACT: CPU_3x2x domain active
    | (0x1  << 26)  // CPU_2XCLKACT:    CPU_2x domain active
    | (0x1  << 27)  // CPU_1XCLKACT:    CPU_1x domain active
    | (0x1  << 28)  // CPU_PERI_CLKACT:
    ;
  REG_SLCR_ARM_CLK_CTRL = v;
  v = REG_SLCR_ARM_PLL_CTRL;
  v |= (1  <<  0);              // PLL_RESET => Assert reset, new PLL values become active
  REG_SLCR_ARM_PLL_CTRL = v;
  v = REG_SLCR_ARM_PLL_CTRL;
  v &= ~(1u << 0);               // PLL_RESET: De-assert
  REG_SLCR_ARM_PLL_CTRL = v;
  do {
    v = REG_SLCR_PLL_STATUS;
  } while ((v & (1 << 0)) == 0); // Wait until locked
  v = REG_SLCR_ARM_PLL_CTRL;
  v &= ~(1u << 4);               // PLL_BYPASS_FORCE: 0 == Remove bypass and switch to PLL
  REG_SLCR_ARM_PLL_CTRL = v;
  //
  // Make sure that we enable CPU_6x and CPU_3x (See clock tree explanation above)
  //
  v = REG_SLCR_CLK_621_TRUE;
  v |= (0x00000001 << 0);        // CLK_621_TRE CLK_621_TRUE (CPU Clock Ratio Mode Select)
  REG_SLCR_CLK_621_TRUE = v;
  //
  // Init DDR PLL
  //
  REG_SLCR_DDR_PLL_CTRL = (1 <<  1); // Power down
  //
  // Init IO_PLL
  //
  v = 0
    | (0x0c  <<  4)  // PLL_RES
    | (0x02  <<  8)  // PLL_CP
    | (0x145 << 12)  // LOCK_CNT
    ;
  REG_SLCR_IO_PLL_CFG = v;
  v = 0
    | (0 <<  1)     // PLL_PWRDWN: 0 == PLL powered up
    | (0 <<  3)     // PLL_BYPASS_QUAL: 0 == Bypass is controlled by PLL_BYPASS_FORCE
    | (1 <<  4)     // PLL_BYPASS_FORCE: 1 == Bypass PLL
    | (0x1E << 12)  // PLL_FDIV: Multiplier for PLL
    ;
  REG_SLCR_IO_PLL_CTRL = v;
  v = REG_SLCR_IO_PLL_CTRL;
  v |= (1  <<  0);           // PLL_RESET => Assert reset, new PLL values become active
  REG_SLCR_IO_PLL_CTRL = v;
  v = REG_SLCR_IO_PLL_CTRL;
  v &= ~(1uL << 0);          // PLL_RESET: De-assert
  REG_SLCR_IO_PLL_CTRL = v;
  do {
    v = REG_SLCR_PLL_STATUS;
  } while ((v & (1 << 2)) == 0); // Wait until locked
  v = REG_SLCR_IO_PLL_CTRL;
  v &= ~(1uL << 4);          // PLL_BYPASS_FORCE: 0 == Remove bypass and switch to PLL
  REG_SLCR_IO_PLL_CTRL = v;
  //
  // Init clock sources for FPGA / programmable logic
  //
  v = 0
    | (0x00000001 << 0) // CLKACT
    | (0x00000000 << 4) // SRCSEL
    | (0x00000005 << 8) // DIVISOR
    ;
  REG_SLCR_PCAP_CLK_CTRL = v;
  v = 0                  // FPGA0 => 200 MHz
    | (0x00000000 <<  4) // SRCSEL
    | (0x00000005 <<  8) // DIVISOR0
    | (0x00000001 << 20) // DIVISOR1
    ;
  REG_SLCR_FPGA0_CLK_CTRL = v;
  v = 0                  // FPGA1 => 1 MHz
    | (0x00000000 <<  4) // SRCSEL
    | (0x00000028 <<  8) // DIVISOR0
    | (0x00000019 << 20) // DIVISOR1
    ;
  REG_SLCR_FPGA1_CLK_CTRL = v;
  v = 0                  // FPGA2 => 1 MHz
    | (0x00000000 <<  4) // SRCSEL
    | (0x00000028 <<  8) // DIVISOR0
    | (0x00000019 << 20) // DIVISOR1
    ;
  REG_SLCR_FPGA2_CLK_CTRL = v;
  v = 0                  // FPGA3 => 1 MHz
    | (0x00000000 <<  4) // SRCSEL
    | (0x00000028 <<  8) // DIVISOR0
    | (0x00000019 << 20) // DIVISOR1
    ;
  REG_SLCR_FPGA3_CLK_CTRL = v;
  REG_SLCR_LOCK = SCLR_LOCK_KEY;
}

/*********************************************************************
*
*       __low_level_init()
*
*  Function description
*    Initialize memory controller, clock generation and PLL
*
*    Has to be modified, if another CPU clock frequency should be
*    used. This function is called during startup and
*    has to return 1 to perform segment initialization.
*
*    Because variables are not initialized before __low_level_init() is called,
*    no access or call which relies on any variable can be used here.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define MEM_ADDR_QSPI_START 0xfc010000
OS_INTERWORK int __low_level_init(void);  // Avoid "no prototype" warning
#ifdef __cplusplus
  }
#endif

OS_INTERWORK int __low_level_init(void) {
  void (*pf)(void);

  REG_SLCR_UNLOCK  = SCLR_UNLOCK_KEY;
  REG_SLCR_OCM_CFG = (1u << 4);  // [2] seems to be set and must kept set it seems. Doc does not say anything about this bit...
  REG_SLCR_LOCK    = SCLR_LOCK_KEY;
  //
  // Initialize PLL, DDR RAM and QSPI flash
  //
  //
  // Initialize PLL and QSPI flash
  // This is a bit hacky but the easiest way to allow BTL sizes > 64 KB
  // As the Zynq copies only 64 KB from QSPI into the iRAM on boot, the BTL size is somewhat limited
  // To get around this, we do the following:
  // We make sure that the _InitPLLs() and _InitQSPI() is in this 64 KB that are copied (made sure via linker file)
  // When calling this function, we are not calling it directly but via function pointer instead
  // This way, we can make sure that we are calling the function copy that is in iRAM and execute it from there
  // It will initialize the PLL and re-inits the QSPI, so that it can safely return to QSPI from the function copy
  //
  pf = (void *)((OS_U32)_InitPLLs - MEM_ADDR_QSPI_START);
  pf();
  pf = (void *)((OS_U32)_InitQSPI - MEM_ADDR_QSPI_START);
  pf();
  //
  //
  // Init MMU and caches. This defines the virtual memory map, which is used during execution.
  // Memory mapping should be complete, meaning 4096 entries.
  // Code below fills in ascending VAddr order
  //
  OS_ARM_MMU_InitTT(_TranslationTable);
  //                                         Mode                               VAddr  PAddr  Size[MB]
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_CACHEMODE_WRITE_BACK_ALLOC, 0x000, 0x000, 0x001);  // 256 KB iRAM, needs to be write back allocate on Zynq since iRAM is very slow (23 cycles)
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_MMU_UNMAPPED,               0x001, 0x001, 0x004);  // DDR-RAM: 1 MB reserved for firmware, 3 MB reserved for future use
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_MMU_UNMAPPED,               0x005, 0x005, 0x07C);  // DDR-RAM: 124 MB reserved for trace buffer which is written by the FPGA (DMA-like)
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_MMU_UNMAPPED,               0x081, 0x005, 0x07C);  // Alias for trace buffer to allow cached access from the CPU
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_CACHEMODE_STRONGLY_ORDERED, 0x0FD, 0x0FD, 0xEB3);  // Make everything strongly ordered until QSPI area
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_CACHEMODE_STRONGLY_ORDERED, 0xFB0, 0x000, 0x001);  // Mapped to 256 KB iRAM @ address 0x0. Necessary for IP stack, which needs an uncached memory pool.
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_MMU_UNMAPPED,               0xFB1, 0x001, 0x004);  // Mapped to first 4 MB of DDR @ 0x100000. Necessary for IP stack, which needs an uncached memory pool.
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_CACHEMODE_STRONGLY_ORDERED, 0xFB5, 0xFB5, 0x00B);  // Everything else is strongly ordered
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_CACHEMODE_WRITE_BACK_ALLOC, 0xFC0, 0xFC0, 0x020);  // QSPI is write back allocate. Seems it needs to be write back alloc to make read caching work correctly. Using write through it seems that L2 lockdown does not have any effect (continuous accesses to QSPI can be seen...)
  OS_ARM_MMU_AddTTEntries(_TranslationTable, OS_ARM_CACHEMODE_STRONGLY_ORDERED, 0xFE0, 0xFE0, 0x020);  // Everything else is strongly ordered
  //
  // Set API functions and base address for L2 Cache
  //
  OS_ARM_AddL2Cache(&OS_L2CACHE_XilinxZynq7000, (void*)L2CACHE_BASE_ADDR);
  //
  // Now enable MMU, Caches and branch prediction unit
  //
  OS_ARM_MMU_Enable(_TranslationTable);
  OS_ARM_ICACHE_Enable();
  OS_ARM_DCACHE_Enable();

  return 1;  // Always return 1 to enable segment initilization !
}

/****** End Of File *************************************************/



回复

使用道具 举报

1

主题

3

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 2023-8-8 19:03:42 | 显示全部楼层
eric2013 发表于 2023-8-8 18:28
现象不同,但反馈的问题都是目标内存访问失败,可以先仅创建一个任务试试,排除野指针和栈溢出。

然后这 ...

好的! 我去试试!感谢硬汉哥!
回复

使用道具 举报

1

主题

3

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 2023-9-8 09:42:20 | 显示全部楼层
最后发现是由于把threadx内核静态编译,但是由于定时器任务栈空间在外部定义没包含到内核中导致的定时器任务栈溢出,ZYNQ内部DDR有一些地址是reserved不可访问读取会报错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-10 20:44 , Processed in 0.169322 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表