mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-20 05:21:59 -04:00
Create directory structure to hold the (not yet created) Keil and IAR demo projects for the SmartFusion.
This commit is contained in:
parent
779e2bf80f
commit
139708e063
168
Demo/CORTEX_A2F200_IAR_and_Keil/FreeRTOSConfig.h
Normal file
168
Demo/CORTEX_A2F200_IAR_and_Keil/FreeRTOSConfig.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
FreeRTOS V7.0.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
|
||||
Atollic AB - Atollic provides professional embedded systems development
|
||||
tools for C/C++ development, code analysis and test automation.
|
||||
See http://www.atollic.com
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
/* The following #error directive is to remind users that a batch file must be
|
||||
* executed prior to this project being built. The batch file *cannot* be
|
||||
* executed from within CCS4! Once it has been executed, re-open or refresh
|
||||
* the CCS4 project and remove the #error line below.
|
||||
*/
|
||||
//#error Ensure CreateProjectDirectoryStructure.bat has been executed before building. See comment immediately above.
|
||||
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Application specific definitions.
|
||||
*
|
||||
* These definitions should be adjusted for your particular hardware and
|
||||
* application requirements.
|
||||
*
|
||||
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
||||
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||
*
|
||||
* See http://www.freertos.org/a00110.html.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configCPU_CLOCK_HZ ( 75000000UL )
|
||||
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
|
||||
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 )
|
||||
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 90 )
|
||||
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 40 * 1024 ) )
|
||||
#define configMAX_TASK_NAME_LEN ( 10 )
|
||||
#define configUSE_TRACE_FACILITY 1
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configQUEUE_REGISTRY_SIZE 0
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 2
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
#define configUSE_MALLOC_FAILED_HOOK 1
|
||||
#define configUSE_APPLICATION_TASK_TAG 0
|
||||
#define configUSE_COUNTING_SEMAPHORES 0
|
||||
|
||||
/* Co-routine definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||
|
||||
/* Software timer definitions. */
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY ( 3 )
|
||||
#define configTIMER_QUEUE_LENGTH 10
|
||||
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 )
|
||||
|
||||
/* Set the following definitions to 1 to include the API function, or zero
|
||||
to exclude the API function. */
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskCleanUpResources 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
|
||||
/* Use the system definition, if there is one */
|
||||
#ifdef __NVIC_PRIO_BITS
|
||||
#define configPRIO_BITS __NVIC_PRIO_BITS
|
||||
#else
|
||||
#define configPRIO_BITS 5 /* 15 priority levels */
|
||||
#endif
|
||||
|
||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x1f
|
||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
||||
|
||||
/* The lowest priority. */
|
||||
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||
/* Priority 5, or 160 as only the top three bits are implemented. */
|
||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||
|
||||
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
|
||||
|
||||
#define vPortSVCHandler SVC_Handler
|
||||
#define xPortPendSVHandler PendSV_Handler
|
||||
#define vPortSVCHandler SVC_Handler
|
||||
#define xPortSysTickHandler SysTick_Handler
|
||||
|
||||
/* MAC address configuration. */
|
||||
#define configMAC_ADDR0 0x00
|
||||
#define configMAC_ADDR1 0x12
|
||||
#define configMAC_ADDR2 0x13
|
||||
#define configMAC_ADDR3 0x10
|
||||
#define configMAC_ADDR4 0x15
|
||||
#define configMAC_ADDR5 0x11
|
||||
|
||||
/* IP address configuration. */
|
||||
#define configIP_ADDR0 192
|
||||
#define configIP_ADDR1 168
|
||||
#define configIP_ADDR2 0
|
||||
#define configIP_ADDR3 200
|
||||
|
||||
/* Netmask configuration. */
|
||||
#define configNET_MASK0 255
|
||||
#define configNET_MASK1 255
|
||||
#define configNET_MASK2 255
|
||||
#define configNET_MASK3 0
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
||||
|
1102
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/CMSIS/a2fxxxm3.h
Normal file
1102
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/CMSIS/a2fxxxm3.h
Normal file
File diff suppressed because it is too large
Load diff
784
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/CMSIS/core_cm3.c
Normal file
784
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/CMSIS/core_cm3.c
Normal file
|
@ -0,0 +1,784 @@
|
|||
/**************************************************************************//**
|
||||
* @file core_cm3.c
|
||||
* @brief CMSIS Cortex-M3 Core Peripheral Access Layer Source File
|
||||
* @version V1.30
|
||||
* @date 30. October 2009
|
||||
*
|
||||
* @note
|
||||
* Copyright (C) 2009 ARM Limited. All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* ARM Limited (ARM) is supplying this software for use with Cortex-M
|
||||
* processor based microcontrollers. This file can be freely distributed
|
||||
* within development tools that are supporting such ARM based processors.
|
||||
*
|
||||
* @par
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
|
||||
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* define compiler specific symbols */
|
||||
#if defined ( __CC_ARM )
|
||||
#define __ASM __asm /*!< asm keyword for ARM Compiler */
|
||||
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
|
||||
|
||||
#elif defined ( __ICCARM__ )
|
||||
#define __ASM __asm /*!< asm keyword for IAR Compiler */
|
||||
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */
|
||||
|
||||
#elif defined ( __GNUC__ )
|
||||
#define __ASM __asm /*!< asm keyword for GNU Compiler */
|
||||
#define __INLINE inline /*!< inline keyword for GNU Compiler */
|
||||
|
||||
#elif defined ( __TASKING__ )
|
||||
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
|
||||
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* ################### Compiler specific Intrinsics ########################### */
|
||||
|
||||
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
|
||||
/* ARM armcc specific functions */
|
||||
|
||||
/**
|
||||
* @brief Return the Process Stack Pointer
|
||||
*
|
||||
* @return ProcessStackPointer
|
||||
*
|
||||
* Return the actual process stack pointer
|
||||
*/
|
||||
__ASM uint32_t __get_PSP(void)
|
||||
{
|
||||
mrs r0, psp
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Process Stack Pointer
|
||||
*
|
||||
* @param topOfProcStack Process Stack Pointer
|
||||
*
|
||||
* Assign the value ProcessStackPointer to the MSP
|
||||
* (process stack pointer) Cortex processor register
|
||||
*/
|
||||
__ASM void __set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
msr psp, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Main Stack Pointer
|
||||
*
|
||||
* @return Main Stack Pointer
|
||||
*
|
||||
* Return the current value of the MSP (main stack pointer)
|
||||
* Cortex processor register
|
||||
*/
|
||||
__ASM uint32_t __get_MSP(void)
|
||||
{
|
||||
mrs r0, msp
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Main Stack Pointer
|
||||
*
|
||||
* @param topOfMainStack Main Stack Pointer
|
||||
*
|
||||
* Assign the value mainStackPointer to the MSP
|
||||
* (main stack pointer) Cortex processor register
|
||||
*/
|
||||
__ASM void __set_MSP(uint32_t mainStackPointer)
|
||||
{
|
||||
msr msp, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in unsigned short value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in unsigned short value
|
||||
*/
|
||||
__ASM uint32_t __REV16(uint16_t value)
|
||||
{
|
||||
rev16 r0, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in signed short value with sign extension to integer
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in signed short value with sign extension to integer
|
||||
*/
|
||||
__ASM int32_t __REVSH(int16_t value)
|
||||
{
|
||||
revsh r0, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
#if (__ARMCC_VERSION < 400000)
|
||||
|
||||
/**
|
||||
* @brief Remove the exclusive lock created by ldrex
|
||||
*
|
||||
* Removes the exclusive lock which is created by ldrex.
|
||||
*/
|
||||
__ASM void __CLREX(void)
|
||||
{
|
||||
clrex
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Base Priority value
|
||||
*
|
||||
* @return BasePriority
|
||||
*
|
||||
* Return the content of the base priority register
|
||||
*/
|
||||
__ASM uint32_t __get_BASEPRI(void)
|
||||
{
|
||||
mrs r0, basepri
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Base Priority value
|
||||
*
|
||||
* @param basePri BasePriority
|
||||
*
|
||||
* Set the base priority register
|
||||
*/
|
||||
__ASM void __set_BASEPRI(uint32_t basePri)
|
||||
{
|
||||
msr basepri, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Priority Mask value
|
||||
*
|
||||
* @return PriMask
|
||||
*
|
||||
* Return state of the priority mask bit from the priority mask register
|
||||
*/
|
||||
__ASM uint32_t __get_PRIMASK(void)
|
||||
{
|
||||
mrs r0, primask
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Priority Mask value
|
||||
*
|
||||
* @param priMask PriMask
|
||||
*
|
||||
* Set the priority mask bit in the priority mask register
|
||||
*/
|
||||
__ASM void __set_PRIMASK(uint32_t priMask)
|
||||
{
|
||||
msr primask, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Fault Mask value
|
||||
*
|
||||
* @return FaultMask
|
||||
*
|
||||
* Return the content of the fault mask register
|
||||
*/
|
||||
__ASM uint32_t __get_FAULTMASK(void)
|
||||
{
|
||||
mrs r0, faultmask
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Fault Mask value
|
||||
*
|
||||
* @param faultMask faultMask value
|
||||
*
|
||||
* Set the fault mask register
|
||||
*/
|
||||
__ASM void __set_FAULTMASK(uint32_t faultMask)
|
||||
{
|
||||
msr faultmask, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Control Register value
|
||||
*
|
||||
* @return Control value
|
||||
*
|
||||
* Return the content of the control register
|
||||
*/
|
||||
__ASM uint32_t __get_CONTROL(void)
|
||||
{
|
||||
mrs r0, control
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Control Register value
|
||||
*
|
||||
* @param control Control value
|
||||
*
|
||||
* Set the control register
|
||||
*/
|
||||
__ASM void __set_CONTROL(uint32_t control)
|
||||
{
|
||||
msr control, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
#endif /* __ARMCC_VERSION */
|
||||
|
||||
|
||||
|
||||
#elif (defined (__ICCARM__)) /*------------------ ICC Compiler -------------------*/
|
||||
/* IAR iccarm specific functions */
|
||||
#pragma diag_suppress=Pe940
|
||||
|
||||
/**
|
||||
* @brief Return the Process Stack Pointer
|
||||
*
|
||||
* @return ProcessStackPointer
|
||||
*
|
||||
* Return the actual process stack pointer
|
||||
*/
|
||||
uint32_t __get_PSP(void)
|
||||
{
|
||||
__ASM("mrs r0, psp");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Process Stack Pointer
|
||||
*
|
||||
* @param topOfProcStack Process Stack Pointer
|
||||
*
|
||||
* Assign the value ProcessStackPointer to the MSP
|
||||
* (process stack pointer) Cortex processor register
|
||||
*/
|
||||
void __set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
__ASM("msr psp, r0");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Main Stack Pointer
|
||||
*
|
||||
* @return Main Stack Pointer
|
||||
*
|
||||
* Return the current value of the MSP (main stack pointer)
|
||||
* Cortex processor register
|
||||
*/
|
||||
uint32_t __get_MSP(void)
|
||||
{
|
||||
__ASM("mrs r0, msp");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Main Stack Pointer
|
||||
*
|
||||
* @param topOfMainStack Main Stack Pointer
|
||||
*
|
||||
* Assign the value mainStackPointer to the MSP
|
||||
* (main stack pointer) Cortex processor register
|
||||
*/
|
||||
void __set_MSP(uint32_t topOfMainStack)
|
||||
{
|
||||
__ASM("msr msp, r0");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in unsigned short value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in unsigned short value
|
||||
*/
|
||||
uint32_t __REV16(uint16_t value)
|
||||
{
|
||||
__ASM("rev16 r0, r0");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse bit order of value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse bit order of value
|
||||
*/
|
||||
uint32_t __RBIT(uint32_t value)
|
||||
{
|
||||
__ASM("rbit r0, r0");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (8 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 8 bit values)
|
||||
*/
|
||||
uint8_t __LDREXB(uint8_t *addr)
|
||||
{
|
||||
__ASM("ldrexb r0, [r0]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (16 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 16 bit values
|
||||
*/
|
||||
uint16_t __LDREXH(uint16_t *addr)
|
||||
{
|
||||
__ASM("ldrexh r0, [r0]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (32 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 32 bit values
|
||||
*/
|
||||
uint32_t __LDREXW(uint32_t *addr)
|
||||
{
|
||||
__ASM("ldrex r0, [r0]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (8 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 8 bit values
|
||||
*/
|
||||
uint32_t __STREXB(uint8_t value, uint8_t *addr)
|
||||
{
|
||||
__ASM("strexb r0, r0, [r1]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (16 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 16 bit values
|
||||
*/
|
||||
uint32_t __STREXH(uint16_t value, uint16_t *addr)
|
||||
{
|
||||
__ASM("strexh r0, r0, [r1]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (32 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 32 bit values
|
||||
*/
|
||||
uint32_t __STREXW(uint32_t value, uint32_t *addr)
|
||||
{
|
||||
__ASM("strex r0, r0, [r1]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
#pragma diag_default=Pe940
|
||||
|
||||
|
||||
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
|
||||
/* GNU gcc specific functions */
|
||||
|
||||
/**
|
||||
* @brief Return the Process Stack Pointer
|
||||
*
|
||||
* @return ProcessStackPointer
|
||||
*
|
||||
* Return the actual process stack pointer
|
||||
*/
|
||||
uint32_t __get_PSP(void) __attribute__( ( naked ) );
|
||||
uint32_t __get_PSP(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, psp\n\t"
|
||||
"MOV r0, %0 \n\t"
|
||||
"BX lr \n\t" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Process Stack Pointer
|
||||
*
|
||||
* @param topOfProcStack Process Stack Pointer
|
||||
*
|
||||
* Assign the value ProcessStackPointer to the MSP
|
||||
* (process stack pointer) Cortex processor register
|
||||
*/
|
||||
void __set_PSP(uint32_t topOfProcStack) __attribute__( ( naked ) );
|
||||
void __set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
__ASM volatile ("MSR psp, %0\n\t"
|
||||
"BX lr \n\t" : : "r" (topOfProcStack) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Main Stack Pointer
|
||||
*
|
||||
* @return Main Stack Pointer
|
||||
*
|
||||
* Return the current value of the MSP (main stack pointer)
|
||||
* Cortex processor register
|
||||
*/
|
||||
uint32_t __get_MSP(void) __attribute__( ( naked ) );
|
||||
uint32_t __get_MSP(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, msp\n\t"
|
||||
"MOV r0, %0 \n\t"
|
||||
"BX lr \n\t" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Main Stack Pointer
|
||||
*
|
||||
* @param topOfMainStack Main Stack Pointer
|
||||
*
|
||||
* Assign the value mainStackPointer to the MSP
|
||||
* (main stack pointer) Cortex processor register
|
||||
*/
|
||||
void __set_MSP(uint32_t topOfMainStack) __attribute__( ( naked ) );
|
||||
void __set_MSP(uint32_t topOfMainStack)
|
||||
{
|
||||
__ASM volatile ("MSR msp, %0\n\t"
|
||||
"BX lr \n\t" : : "r" (topOfMainStack) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Base Priority value
|
||||
*
|
||||
* @return BasePriority
|
||||
*
|
||||
* Return the content of the base priority register
|
||||
*/
|
||||
uint32_t __get_BASEPRI(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, basepri_max" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Base Priority value
|
||||
*
|
||||
* @param basePri BasePriority
|
||||
*
|
||||
* Set the base priority register
|
||||
*/
|
||||
void __set_BASEPRI(uint32_t value)
|
||||
{
|
||||
__ASM volatile ("MSR basepri, %0" : : "r" (value) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Priority Mask value
|
||||
*
|
||||
* @return PriMask
|
||||
*
|
||||
* Return state of the priority mask bit from the priority mask register
|
||||
*/
|
||||
uint32_t __get_PRIMASK(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, primask" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Priority Mask value
|
||||
*
|
||||
* @param priMask PriMask
|
||||
*
|
||||
* Set the priority mask bit in the priority mask register
|
||||
*/
|
||||
void __set_PRIMASK(uint32_t priMask)
|
||||
{
|
||||
__ASM volatile ("MSR primask, %0" : : "r" (priMask) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Fault Mask value
|
||||
*
|
||||
* @return FaultMask
|
||||
*
|
||||
* Return the content of the fault mask register
|
||||
*/
|
||||
uint32_t __get_FAULTMASK(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, faultmask" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Fault Mask value
|
||||
*
|
||||
* @param faultMask faultMask value
|
||||
*
|
||||
* Set the fault mask register
|
||||
*/
|
||||
void __set_FAULTMASK(uint32_t faultMask)
|
||||
{
|
||||
__ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Control Register value
|
||||
*
|
||||
* @return Control value
|
||||
*
|
||||
* Return the content of the control register
|
||||
*/
|
||||
uint32_t __get_CONTROL(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, control" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Control Register value
|
||||
*
|
||||
* @param control Control value
|
||||
*
|
||||
* Set the control register
|
||||
*/
|
||||
void __set_CONTROL(uint32_t control)
|
||||
{
|
||||
__ASM volatile ("MSR control, %0" : : "r" (control) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in integer value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in integer value
|
||||
*/
|
||||
uint32_t __REV(uint32_t value)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in unsigned short value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in unsigned short value
|
||||
*/
|
||||
uint32_t __REV16(uint16_t value)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in signed short value with sign extension to integer
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in signed short value with sign extension to integer
|
||||
*/
|
||||
int32_t __REVSH(int16_t value)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse bit order of value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse bit order of value
|
||||
*/
|
||||
uint32_t __RBIT(uint32_t value)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (8 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 8 bit value
|
||||
*/
|
||||
uint8_t __LDREXB(uint8_t *addr)
|
||||
{
|
||||
uint8_t result=0;
|
||||
|
||||
__ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (16 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 16 bit values
|
||||
*/
|
||||
uint16_t __LDREXH(uint16_t *addr)
|
||||
{
|
||||
uint16_t result=0;
|
||||
|
||||
__ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (32 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 32 bit values
|
||||
*/
|
||||
uint32_t __LDREXW(uint32_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (8 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 8 bit values
|
||||
*/
|
||||
uint32_t __STREXB(uint8_t value, uint8_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (16 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 16 bit values
|
||||
*/
|
||||
uint32_t __STREXH(uint16_t value, uint16_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (32 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 32 bit values
|
||||
*/
|
||||
uint32_t __STREXW(uint32_t value, uint32_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("strex %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
#elif (defined (__TASKING__)) /*------------------ TASKING Compiler ---------------------*/
|
||||
/* TASKING carm specific functions */
|
||||
|
||||
/*
|
||||
* The CMSIS functions have been implemented as intrinsics in the compiler.
|
||||
* Please use "carm -?i" to get an up to date list of all instrinsics,
|
||||
* Including the CMSIS ones.
|
||||
*/
|
||||
|
||||
#endif
|
1818
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/CMSIS/core_cm3.h
Normal file
1818
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/CMSIS/core_cm3.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,48 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* Assertion implementation.
|
||||
*
|
||||
* This file provides the implementation of the ASSERT macro. This file can be
|
||||
* modified to cater for project specific requirements regarding the way
|
||||
* assertions are handled.
|
||||
*
|
||||
* SVN $Revision: 1676 $
|
||||
* SVN $Date: 2009-12-02 16:47:03 +0000 (Wed, 02 Dec 2009) $
|
||||
*/
|
||||
#ifndef __MSS_ASSERT_H_
|
||||
#define __MSS_ASSERT_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if defined ( __GNUC__ )
|
||||
|
||||
#if defined(NDEBUG)
|
||||
|
||||
#define ASSERT(CHECK)
|
||||
|
||||
#else /* NDEBUG */
|
||||
/*
|
||||
* SoftConsole assertion handling
|
||||
*/
|
||||
#define ASSERT(CHECK) \
|
||||
do { \
|
||||
if (!(CHECK)) \
|
||||
{ \
|
||||
__asm volatile ("BKPT\n\t"); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#endif /* NDEBUG */
|
||||
|
||||
#else
|
||||
/*
|
||||
* IAR Embedded Workbench or Keil assertion handling.
|
||||
* Call C library assert function which should result in error message
|
||||
* displayed in debugger.
|
||||
*/
|
||||
#define ASSERT(X) assert(X)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_ASSERT_H_ */
|
|
@ -0,0 +1,184 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion/Cortex-M3 linker script for creating a SoftConsole downloadable
|
||||
* debug image executing in SmartFusion internal eNVM.
|
||||
*
|
||||
* SVN $Revision: 1677 $
|
||||
* SVN $Date: 2009-12-02 16:57:29 +0000 (Wed, 02 Dec 2009) $
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
|
||||
"elf32-littlearm")
|
||||
GROUP(-lc -lgcc -lm)
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(Reset_Handler)
|
||||
SEARCH_DIR(.)
|
||||
__DYNAMIC = 0;
|
||||
|
||||
/*******************************************************************************
|
||||
* Start of board customization.
|
||||
*******************************************************************************/
|
||||
MEMORY
|
||||
{
|
||||
/*
|
||||
* WARNING: The words "SOFTCONSOLE", "FLASH", and "USE", the colon ":", and
|
||||
* the name of the type of flash memory are all in a specific order.
|
||||
* Please do not modify that comment line, in order to ensure
|
||||
* debugging of your application will use the flash memory correctly.
|
||||
*/
|
||||
|
||||
/* SOFTCONSOLE FLASH USE: actel-smartfusion-envm */
|
||||
rom (rx) : ORIGIN = 0x60000000, LENGTH = 256k
|
||||
|
||||
/* SmartFusion internal eNVM mirrored to 0x00000000 */
|
||||
romMirror (rx) : ORIGIN = 0x00000000, LENGTH = 256k
|
||||
|
||||
/* SmartFusion internal eSRAM */
|
||||
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
|
||||
}
|
||||
|
||||
RAM_START_ADDRESS = 0x20000000; /* Must be the same value MEMORY region ram ORIGIN above. */
|
||||
RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */
|
||||
MAIN_STACK_SIZE = 8k; /* Cortex main stack size. */
|
||||
PROCESS_STACK_SIZE = 4k; /* Cortex process stack size (only available with OS extensions).*/
|
||||
|
||||
/*******************************************************************************
|
||||
* End of board customization.
|
||||
*******************************************************************************/
|
||||
|
||||
PROVIDE (__main_stack_start = RAM_START_ADDRESS + RAM_SIZE);
|
||||
PROVIDE (__process_stack_start = __main_stack_start - MAIN_STACK_SIZE);
|
||||
PROVIDE (_estack = __main_stack_start);
|
||||
PROVIDE (__mirrored_nvm = 1); /* Indicate to startup code that NVM is mirrored to VMA address and no text copy is required. */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.init :
|
||||
{
|
||||
*(.isr_vector)
|
||||
*sys_boot.o(.text)
|
||||
. = ALIGN(0x4);
|
||||
} >romMirror AT>rom
|
||||
|
||||
.text :
|
||||
{
|
||||
CREATE_OBJECT_SYMBOLS
|
||||
__text_load = LOADADDR(.text);
|
||||
__text_start = .;
|
||||
|
||||
*(.text .text.* .gnu.linkonce.t.*)
|
||||
*(.plt)
|
||||
*(.gnu.warning)
|
||||
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
|
||||
|
||||
. = ALIGN(0x4);
|
||||
/* These are for running static constructors and destructors under ELF. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*crtend.o(.ctors))
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*crtend.o(.dtors))
|
||||
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
*(.gcc_except_table)
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame)
|
||||
|
||||
KEEP (*(.init))
|
||||
KEEP (*(.fini))
|
||||
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} >romMirror AT>rom
|
||||
|
||||
/* .ARM.exidx is sorted, so has to go in its own output section. */
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} >ram AT>rom
|
||||
__exidx_end = .;
|
||||
_etext = .;
|
||||
|
||||
.data :
|
||||
{
|
||||
__data_load = LOADADDR(.data);
|
||||
_sidata = LOADADDR (.data);
|
||||
__data_start = .;
|
||||
_sdata = .;
|
||||
KEEP(*(.jcr))
|
||||
*(.got.plt) *(.got)
|
||||
*(.shdata)
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
. = ALIGN (4);
|
||||
_edata = .;
|
||||
} >ram AT>rom
|
||||
|
||||
.bss :
|
||||
{
|
||||
__bss_start__ = . ;
|
||||
_sbss = .;
|
||||
*(.shbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
__bss_end__ = .;
|
||||
_end = .;
|
||||
__end = _end;
|
||||
_ebss = .;
|
||||
PROVIDE(end = .);
|
||||
} >ram AT>rom
|
||||
|
||||
.stab 0 (NOLOAD) :
|
||||
{
|
||||
*(.stab)
|
||||
}
|
||||
|
||||
.stabstr 0 (NOLOAD) :
|
||||
{
|
||||
*(.stabstr)
|
||||
}
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
|
||||
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
|
||||
/DISCARD/ : { *(.note.GNU-stack) }
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion/Cortex-M3 linker script for creating a SoftConsole downloadable
|
||||
* debug image executing in SmartFusion internal eSRAM.
|
||||
*
|
||||
* SVN $Revision: 1677 $
|
||||
* SVN $Date: 2009-12-02 16:57:29 +0000 (Wed, 02 Dec 2009) $
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
|
||||
"elf32-littlearm")
|
||||
GROUP(-lc -lgcc -lm)
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(Reset_Handler)
|
||||
SEARCH_DIR(.)
|
||||
__DYNAMIC = 0;
|
||||
|
||||
/*******************************************************************************
|
||||
* Start of board customization.
|
||||
*******************************************************************************/
|
||||
MEMORY
|
||||
{
|
||||
/* SmartFusion internal eSRAM */
|
||||
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
|
||||
}
|
||||
|
||||
RAM_START_ADDRESS = 0x20000000; /* Must be the same value MEMORY region ram ORIGIN above. */
|
||||
RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */
|
||||
MAIN_STACK_SIZE = 8k; /* Cortex main stack size. */
|
||||
PROCESS_STACK_SIZE = 4k; /* Cortex process stack size (only available with OS extensions).*/
|
||||
|
||||
/*******************************************************************************
|
||||
* End of board customization.
|
||||
*******************************************************************************/
|
||||
|
||||
PROVIDE (__main_stack_start = RAM_START_ADDRESS + RAM_SIZE);
|
||||
PROVIDE (__process_stack_start = __main_stack_start - MAIN_STACK_SIZE);
|
||||
PROVIDE (_estack = __main_stack_start);
|
||||
PROVIDE (__mirrored_nvm = 0); /* Indicate to startup code that NVM is not mirrored to VMA address .text copy is required. */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
CREATE_OBJECT_SYMBOLS
|
||||
__text_load = LOADADDR(.text);
|
||||
__text_start = .;
|
||||
*(.isr_vector)
|
||||
*(.text .text.* .gnu.linkonce.t.*)
|
||||
*(.plt)
|
||||
*(.gnu.warning)
|
||||
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
|
||||
|
||||
. = ALIGN(0x4);
|
||||
/* These are for running static constructors and destructors under ELF. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*crtend.o(.ctors))
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*crtend.o(.dtors))
|
||||
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
*(.gcc_except_table)
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame)
|
||||
|
||||
KEEP (*(.init))
|
||||
KEEP (*(.fini))
|
||||
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} >ram
|
||||
/* .ARM.exidx is sorted, so has to go in its own output section. */
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} >ram
|
||||
__exidx_end = .;
|
||||
_etext = .;
|
||||
PROVIDE(__text_end = .);
|
||||
|
||||
.data :
|
||||
{
|
||||
__data_load = LOADADDR (.data);
|
||||
_sidata = LOADADDR (.data);
|
||||
__data_start = .;
|
||||
_sdata = .;
|
||||
KEEP(*(.jcr))
|
||||
*(.got.plt) *(.got)
|
||||
*(.shdata)
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
. = ALIGN (4);
|
||||
_edata = .;
|
||||
} >ram
|
||||
|
||||
.bss :
|
||||
{
|
||||
__bss_start__ = . ;
|
||||
_sbss = .;
|
||||
*(.shbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
__bss_end__ = .;
|
||||
_end = .;
|
||||
__end = _end;
|
||||
_ebss = .;
|
||||
PROVIDE(end = .);
|
||||
} >ram
|
||||
|
||||
/*
|
||||
* The .stack section is only specified here in order for the linker to generate
|
||||
* an error if the ram is full.
|
||||
*/
|
||||
.stack :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
. += PROCESS_STACK_SIZE;
|
||||
. = ALIGN(4);
|
||||
. += MAIN_STACK_SIZE;
|
||||
. = ALIGN(4);
|
||||
} >ram
|
||||
|
||||
.stab 0 (NOLOAD) :
|
||||
{
|
||||
*(.stab)
|
||||
}
|
||||
|
||||
.stabstr 0 (NOLOAD) :
|
||||
{
|
||||
*(.stabstr)
|
||||
}
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
|
||||
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
|
||||
/DISCARD/ : { *(.note.GNU-stack) *(.isr_vector) }
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion/Cortex-M3 linker script for creating a SoftConsole downloadable
|
||||
* debug image executing in SmartFusion development board external RAM.
|
||||
*
|
||||
* SVN $Revision: 2014 $
|
||||
* SVN $Date: 2010-01-20 10:37:26 +0000 (Wed, 20 Jan 2010) $
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
|
||||
"elf32-littlearm")
|
||||
GROUP(-lc -lgcc -lm)
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(Reset_Handler)
|
||||
SEARCH_DIR(.)
|
||||
__DYNAMIC = 0;
|
||||
|
||||
/*******************************************************************************
|
||||
* Start of board customization.
|
||||
*******************************************************************************/
|
||||
MEMORY
|
||||
{
|
||||
/* SmartFusion internal eSRAM */
|
||||
esram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
|
||||
|
||||
/* SmartFusion development board external RAM */
|
||||
external_ram (rwx) : ORIGIN = 0x70000000, LENGTH = 2M
|
||||
}
|
||||
|
||||
RAM_START_ADDRESS = 0x70000000; /* Must be the same value MEMORY region ram ORIGIN above. */
|
||||
RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */
|
||||
MAIN_STACK_SIZE = 8k; /* Cortex main stack size. */
|
||||
PROCESS_STACK_SIZE = 4k; /* Cortex process stack size (only available with OS extensions).*/
|
||||
|
||||
/*******************************************************************************
|
||||
* End of board customization.
|
||||
*******************************************************************************/
|
||||
|
||||
PROVIDE (__main_stack_start = RAM_START_ADDRESS + RAM_SIZE);
|
||||
PROVIDE (__process_stack_start = __main_stack_start - MAIN_STACK_SIZE);
|
||||
PROVIDE (_estack = __main_stack_start);
|
||||
PROVIDE (__mirrored_nvm = 0); /* Indicate to startup code that NVM is not mirrored to VMA address .text copy is required. */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.init :
|
||||
{
|
||||
*(.isr_vector)
|
||||
. = ALIGN(0x4);
|
||||
} >esram
|
||||
|
||||
.text :
|
||||
{
|
||||
CREATE_OBJECT_SYMBOLS
|
||||
__text_load = LOADADDR(.text);
|
||||
__text_start = .;
|
||||
*(.text .text.* .gnu.linkonce.t.*)
|
||||
*(.plt)
|
||||
*(.gnu.warning)
|
||||
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
|
||||
|
||||
. = ALIGN(0x4);
|
||||
/* These are for running static constructors and destructors under ELF. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*crtend.o(.ctors))
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*crtend.o(.dtors))
|
||||
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
*(.gcc_except_table)
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame)
|
||||
|
||||
KEEP (*(.init))
|
||||
KEEP (*(.fini))
|
||||
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} >external_ram
|
||||
/* .ARM.exidx is sorted, so has to go in its own output section. */
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} >external_ram
|
||||
__exidx_end = .;
|
||||
_etext = .;
|
||||
PROVIDE(__text_end = .);
|
||||
|
||||
.data :
|
||||
{
|
||||
__data_load = LOADADDR (.data);
|
||||
_sidata = LOADADDR (.data);
|
||||
__data_start = .;
|
||||
_sdata = .;
|
||||
KEEP(*(.jcr))
|
||||
*(.got.plt) *(.got)
|
||||
*(.shdata)
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
. = ALIGN (4);
|
||||
_edata = .;
|
||||
} >external_ram
|
||||
|
||||
.bss :
|
||||
{
|
||||
__bss_start__ = . ;
|
||||
_sbss = .;
|
||||
*(.shbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
__bss_end__ = .;
|
||||
_end = .;
|
||||
__end = _end;
|
||||
_ebss = .;
|
||||
PROVIDE(end = .);
|
||||
} >external_ram
|
||||
|
||||
/*
|
||||
* The .stack section is only specified here in order for the linker to generate
|
||||
* an error if the esram is full.
|
||||
*/
|
||||
.stack :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
. += PROCESS_STACK_SIZE;
|
||||
. = ALIGN(4);
|
||||
. += MAIN_STACK_SIZE;
|
||||
. = ALIGN(4);
|
||||
} >external_ram
|
||||
|
||||
.stab 0 (NOLOAD) :
|
||||
{
|
||||
*(.stab)
|
||||
}
|
||||
|
||||
.stabstr 0 (NOLOAD) :
|
||||
{
|
||||
*(.stabstr)
|
||||
}
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
|
||||
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
|
||||
/DISCARD/ : { *(.note.GNU-stack) *(.isr_vector) }
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* Stubs for Newlib system calls.
|
||||
*
|
||||
* SVN $Revision: 2020 $
|
||||
* SVN $Date: 2010-01-20 14:51:50 +0000 (Wed, 20 Jan 2010) $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/times.h>
|
||||
#include <errno.h>
|
||||
#undef errno
|
||||
extern int errno;
|
||||
|
||||
/*==============================================================================
|
||||
* Redirection of standard output to a SmartFusion MSS UART.
|
||||
*------------------------------------------------------------------------------
|
||||
* A default implementation for the redirection of the output of printf() to a
|
||||
* UART is provided as the bottom of this file. This redirection is enabled by
|
||||
* adding the symbol/define ACTEL_STDIO_THRU_UART to your project and
|
||||
* specifying the baud rate using the ACTEL_STDIO_BAUD_RATE define.
|
||||
*/
|
||||
#ifdef ACTEL_STDIO_THRU_UART
|
||||
#include "../../drivers/mss_uart/mss_uart.h"
|
||||
|
||||
#ifndef ACTEL_STDIO_BAUD_RATE
|
||||
#define ACTEL_STDIO_BAUD_RATE MSS_UART_57600_BAUD
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Global flag used to indicate if the UART driver needs to be initialized.
|
||||
*/
|
||||
static int g_stdio_uart_init_done = 0;
|
||||
|
||||
#endif /* ACTEL_STDIO_THRU_UART */
|
||||
|
||||
/*==============================================================================
|
||||
* Environment variables.
|
||||
* A pointer to a list of environment variables and their values. For a minimal
|
||||
* environment, this empty list is adequate:
|
||||
*/
|
||||
char *__env[1] = { 0 };
|
||||
char **environ = __env;
|
||||
|
||||
/*==============================================================================
|
||||
* Close a file.
|
||||
*/
|
||||
int _close(int file)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Transfer control to a new process.
|
||||
*/
|
||||
int _execve(char *name, char **argv, char **env)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Exit a program without cleaning up files.
|
||||
*/
|
||||
void _exit( int code )
|
||||
{
|
||||
/* Should we force a system reset? */
|
||||
while( 1 )
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Create a new process.
|
||||
*/
|
||||
int _fork(void)
|
||||
{
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Status of an open file.
|
||||
*/
|
||||
int _fstat(int file, struct stat *st)
|
||||
{
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Process-ID
|
||||
*/
|
||||
int _getpid(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Query whether output stream is a terminal.
|
||||
*/
|
||||
int _isatty(int file)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Send a signal.
|
||||
*/
|
||||
int _kill(int pid, int sig)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Establish a new name for an existing file.
|
||||
*/
|
||||
int _link(char *old, char *new)
|
||||
{
|
||||
errno = EMLINK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Set position in a file.
|
||||
*/
|
||||
int _lseek(int file, int ptr, int dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Open a file.
|
||||
*/
|
||||
int _open(const char *name, int flags, int mode)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Read from a file.
|
||||
*/
|
||||
int _read(int file, char *ptr, int len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Increase program data space. As malloc and related functions depend on this,
|
||||
* it is useful to have a working implementation. The following suffices for a
|
||||
* standalone system; it exploits the symbol _end automatically defined by the
|
||||
* GNU linker.
|
||||
*/
|
||||
caddr_t _sbrk(int incr)
|
||||
{
|
||||
extern char _end; /* Defined by the linker */
|
||||
static char *heap_end;
|
||||
char *prev_heap_end;
|
||||
char * stack_ptr;
|
||||
|
||||
if (heap_end == 0)
|
||||
{
|
||||
heap_end = &_end;
|
||||
}
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
asm volatile ("MRS %0, msp" : "=r" (stack_ptr) );
|
||||
if (heap_end + incr > stack_ptr)
|
||||
{
|
||||
write (1, "Heap and stack collision\n", 25);
|
||||
abort ();
|
||||
}
|
||||
|
||||
heap_end += incr;
|
||||
return (caddr_t) prev_heap_end;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Status of a file (by name).
|
||||
*/
|
||||
int _stat(char *file, struct stat *st)
|
||||
{
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Timing information for current process.
|
||||
*/
|
||||
int _times(struct tms *buf)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Remove a file's directory entry.
|
||||
*/
|
||||
int _unlink(char *name)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Wait for a child process.
|
||||
*/
|
||||
int _wait(int *status)
|
||||
{
|
||||
errno = ECHILD;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Write to a file. libc subroutines will use this system routine for output to
|
||||
* all files, including stdout—so if you need to generate any output, for
|
||||
* example to a serial port for debugging, you should make your minimal write
|
||||
* capable of doing this.
|
||||
*/
|
||||
int _write_r( void * reent, int file, char * ptr, int len )
|
||||
{
|
||||
#ifdef ACTEL_STDIO_THRU_UART
|
||||
/*--------------------------------------------------------------------------
|
||||
* Initialize the UART driver if it is the first time this function is
|
||||
* called.
|
||||
*/
|
||||
if ( !g_stdio_uart_init_done )
|
||||
{
|
||||
MSS_UART_init( &g_mss_uart0, ACTEL_STDIO_BAUD_RATE, (MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY));
|
||||
g_stdio_uart_init_done = 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
* Output text to the UART.
|
||||
*/
|
||||
MSS_UART_polled_tx( &g_mss_uart0, (uint8_t *)ptr, len );
|
||||
|
||||
return len;
|
||||
#else /* ACTEL_STDIO_THRU_UART */
|
||||
return 0;
|
||||
#endif /* ACTEL_STDIO_THRU_UART */
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion/Cortex-M3 linker script creating an executable image for use in
|
||||
* the Libero flow for executing code in place in internal eNVM.
|
||||
*
|
||||
* SVN $Revision: 1766 $
|
||||
* SVN $Date: 2009-12-11 16:33:35 +0000 (Fri, 11 Dec 2009) $
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
|
||||
"elf32-littlearm")
|
||||
GROUP(-lc -lgcc -lm)
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(Reset_Handler)
|
||||
SEARCH_DIR(.)
|
||||
__DYNAMIC = 0;
|
||||
|
||||
/*******************************************************************************
|
||||
* Start of board customization.
|
||||
*******************************************************************************/
|
||||
MEMORY
|
||||
{
|
||||
/* SmartFusion internal eNVM */
|
||||
rom (rx) : ORIGIN = 0, LENGTH = 256k
|
||||
|
||||
/* SmartFusion internal eSRAM */
|
||||
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
|
||||
}
|
||||
|
||||
RAM_START_ADDRESS = 0x20000000; /* Must be the same value as MEMORY region ram ORIGIN above. */
|
||||
RAM_SIZE = 64k; /* Must be the same value as MEMORY region ram LENGTH above. */
|
||||
MAIN_STACK_SIZE = 8k; /* Cortex main stack size. */
|
||||
PROCESS_STACK_SIZE = 4k; /* Cortex process stack size (only available with OS extensions).*/
|
||||
|
||||
/*******************************************************************************
|
||||
* End of board customization.
|
||||
*******************************************************************************/
|
||||
|
||||
PROVIDE (__main_stack_start = RAM_START_ADDRESS + RAM_SIZE);
|
||||
PROVIDE (__process_stack_start = __main_stack_start - MAIN_STACK_SIZE);
|
||||
PROVIDE (_estack = __main_stack_start);
|
||||
PROVIDE (__mirrored_nvm = 0); /* Indicate to startup code that NVM is not mirrored to VMA address .text copy is required. */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.reset :
|
||||
{
|
||||
*(.isr_vector)
|
||||
*sys_boot.o(.text)
|
||||
. = ALIGN(0x4);
|
||||
} >rom
|
||||
|
||||
.text :
|
||||
{
|
||||
CREATE_OBJECT_SYMBOLS
|
||||
__text_load = LOADADDR(.text);
|
||||
__text_start = .;
|
||||
|
||||
*(.text .text.* .gnu.linkonce.t.*)
|
||||
*(.plt)
|
||||
*(.gnu.warning)
|
||||
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
|
||||
|
||||
. = ALIGN(0x4);
|
||||
/* These are for running static constructors and destructors under ELF. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*crtend.o(.ctors))
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*crtend.o(.dtors))
|
||||
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
*(.gcc_except_table)
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame)
|
||||
|
||||
KEEP (*(.init))
|
||||
KEEP (*(.fini))
|
||||
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} >rom
|
||||
/* .ARM.exidx is sorted, so has to go in its own output section. */
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} >rom
|
||||
__exidx_end = .;
|
||||
_etext = .;
|
||||
|
||||
.data :
|
||||
{
|
||||
__data_load = LOADADDR(.data);
|
||||
_sidata = LOADADDR (.data);
|
||||
__data_start = .;
|
||||
_sdata = .;
|
||||
KEEP(*(.jcr))
|
||||
*(.got.plt) *(.got)
|
||||
*(.shdata)
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
. = ALIGN (4);
|
||||
_edata = .;
|
||||
} >ram AT>rom
|
||||
|
||||
.bss :
|
||||
{
|
||||
__bss_start__ = . ;
|
||||
_sbss = .;
|
||||
*(.shbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
__bss_end__ = .;
|
||||
_end = .;
|
||||
__end = _end;
|
||||
_ebss = .;
|
||||
PROVIDE(end = .);
|
||||
} >ram AT>rom
|
||||
|
||||
.stab 0 (NOLOAD) :
|
||||
{
|
||||
*(.stab)
|
||||
}
|
||||
|
||||
.stabstr 0 (NOLOAD) :
|
||||
{
|
||||
*(.stabstr)
|
||||
}
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
|
||||
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
|
||||
/DISCARD/ : { *(.note.GNU-stack) }
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion/Cortex-M3 linker script creating an executable image for use in
|
||||
* the Libero flow for relocating executable from internal eNVM to external RAM
|
||||
* before starting execution.
|
||||
*
|
||||
* SVN $Revision: 1766 $
|
||||
* SVN $Date: 2009-12-11 16:33:35 +0000 (Fri, 11 Dec 2009) $
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
|
||||
"elf32-littlearm")
|
||||
GROUP(-lc -lgcc -lm)
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(Reset_Handler)
|
||||
SEARCH_DIR(.)
|
||||
__DYNAMIC = 0;
|
||||
|
||||
/*******************************************************************************
|
||||
* Start of board customization.
|
||||
*******************************************************************************/
|
||||
MEMORY
|
||||
{
|
||||
/* SmartFusion internal eNVM */
|
||||
rom (rx) : ORIGIN = 0, LENGTH = 256k
|
||||
|
||||
/* SmartFusion internal eSRAM */
|
||||
esram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
|
||||
|
||||
/* SmartFusion development board external RAM */
|
||||
external_ram (rwx) : ORIGIN = 0x70000000, LENGTH = 2M
|
||||
}
|
||||
|
||||
RAM_START_ADDRESS = 0x20000000; /* Must be the same value as MEMORY region esram ORIGIN above. */
|
||||
RAM_SIZE = 64k; /* Must be the same value as MEMORY region esram LENGTH above. */
|
||||
MAIN_STACK_SIZE = 8k; /* Cortex main stack size. */
|
||||
PROCESS_STACK_SIZE = 4k; /* Cortex process stack size (only available with OS extensions).*/
|
||||
|
||||
/*******************************************************************************
|
||||
* End of board customization.
|
||||
*******************************************************************************/
|
||||
|
||||
PROVIDE (__main_stack_start = RAM_START_ADDRESS + RAM_SIZE);
|
||||
PROVIDE (__process_stack_start = __main_stack_start - MAIN_STACK_SIZE);
|
||||
PROVIDE (_estack = __main_stack_start);
|
||||
PROVIDE (__mirrored_nvm = 0); /* Indicate to startup code that NVM is not mirrored to VMA address .text copy is required. */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.reset :
|
||||
{
|
||||
*(.isr_vector)
|
||||
/* *sys_boot.o(.text)*/
|
||||
. = ALIGN(0x4);
|
||||
} >rom
|
||||
|
||||
.text :
|
||||
{
|
||||
CREATE_OBJECT_SYMBOLS
|
||||
__text_load = LOADADDR(.text);
|
||||
__text_start = .;
|
||||
|
||||
*(.text .text.* .gnu.linkonce.t.*)
|
||||
*(.plt)
|
||||
*(.gnu.warning)
|
||||
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
|
||||
|
||||
. = ALIGN(0x4);
|
||||
/* These are for running static constructors and destructors under ELF. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*crtend.o(.ctors))
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*crtend.o(.dtors))
|
||||
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
*(.gcc_except_table)
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame)
|
||||
|
||||
KEEP (*(.init))
|
||||
KEEP (*(.fini))
|
||||
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} >external_ram AT>rom
|
||||
/* .ARM.exidx is sorted, so has to go in its own output section. */
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} >external_ram AT>rom
|
||||
__exidx_end = .;
|
||||
_etext = .;
|
||||
|
||||
.data :
|
||||
{
|
||||
__data_load = LOADADDR(.data);
|
||||
_sidata = LOADADDR (.data);
|
||||
__data_start = .;
|
||||
_sdata = .;
|
||||
KEEP(*(.jcr))
|
||||
*(.got.plt) *(.got)
|
||||
*(.shdata)
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
. = ALIGN (4);
|
||||
_edata = .;
|
||||
} >esram AT>rom
|
||||
|
||||
.bss :
|
||||
{
|
||||
__bss_start__ = . ;
|
||||
_sbss = .;
|
||||
*(.shbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
__bss_end__ = .;
|
||||
_end = .;
|
||||
__end = _end;
|
||||
_ebss = .;
|
||||
PROVIDE(end = .);
|
||||
} >esram AT>rom
|
||||
|
||||
.stab 0 (NOLOAD) :
|
||||
{
|
||||
*(.stab)
|
||||
}
|
||||
|
||||
.stabstr 0 (NOLOAD) :
|
||||
{
|
||||
*(.stabstr)
|
||||
}
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
|
||||
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
|
||||
/DISCARD/ : { *(.note.GNU-stack) }
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,199 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion A2FxxxM3 CMSIS system initialization.
|
||||
*
|
||||
* SVN $Revision: 2069 $
|
||||
* SVN $Date: 2010-01-28 00:23:48 +0000 (Thu, 28 Jan 2010) $
|
||||
*/
|
||||
#include "a2fxxxm3.h"
|
||||
#include "mss_assert.h"
|
||||
|
||||
/* System frequency (FCLK) coming out of reset is 25MHz. */
|
||||
#define RESET_SYSCLCK_FREQ 25000000uL
|
||||
|
||||
/*
|
||||
* SmartFusion Microcontroller Subsystem FLCK frequency.
|
||||
* The value of SMARTFUSION_FCLK_FREQ is used to report the system's clock
|
||||
* frequency in system's which either do not use the Actel System Boot or
|
||||
* a version of the Actel System Boot older than 1.3.1. In eitehr of these cases
|
||||
* SMARTFUSION_FCLK_FREQ should be defined in the projects settings to reflect
|
||||
* the FCLK frequency selected in the Libero MSS configurator.
|
||||
* Systems using the Actel System Boot version 1.3.1 or later do not require this
|
||||
* define since the system's frequency is retrieved from eNVM spare pages where
|
||||
* the MSS Configurator stored the frequency selected during hardware design/configuration.
|
||||
*/
|
||||
#ifdef SMARTFUSION_FCLK_FREQ
|
||||
#define SMARTFUSION_FCLK_FREQ_DEFINED 1
|
||||
#else
|
||||
#define SMARTFUSION_FCLK_FREQ_DEFINED 0
|
||||
#define SMARTFUSION_FCLK_FREQ RESET_SYSCLCK_FREQ
|
||||
#endif
|
||||
|
||||
/* Divider values for APB0, APB1 and ACE clocks. */
|
||||
#define RESET_PCLK0_DIV 4uL
|
||||
#define RESET_PCLK1_DIV 4uL
|
||||
#define RESET_ACE_DIV 4uL
|
||||
#define RESET_FPGA_CLK_DIV 4uL
|
||||
|
||||
/* System register clock control mask and shift for PCLK dividers. */
|
||||
#define PCLK_DIV_MASK 0x00000003uL
|
||||
#define PCLK0_DIV_SHIFT 2uL
|
||||
#define PCLK1_DIV_SHIFT 4uL
|
||||
#define ACE_DIV_SHIFT 6uL
|
||||
|
||||
/* System register MSS_CCC_DIV_CR mask and shift for GLB (FPGA fabric clock). */
|
||||
#define OBDIV_SHIFT 8uL
|
||||
#define OBDIV_MASK 0x0000001FuL
|
||||
#define OBDIVHALF_SHIFT 13uL
|
||||
#define OBDIVHALF_MASK 0x00000001uL
|
||||
|
||||
/*
|
||||
* Actel system boot version defines used to extract the system clock from eNVM
|
||||
* spare pages.
|
||||
* These defines allow detecting the presence of Actel system boot in eNVM spare
|
||||
* pages and the version of that system boot executable and associated
|
||||
* configuration data.
|
||||
*/
|
||||
#define SYSBOOT_KEY_ADDR (uint32_t *)0x6008081C
|
||||
#define SYSBOOT_KEY_VALUE 0x4C544341uL
|
||||
#define SYSBOOT_VERSION_ADDR (uint32_t *)0x60080840
|
||||
#define SYSBOOT_1_3_FCLK_ADDR (uint32_t *)0x6008162C
|
||||
#define SYSBOOT_2_x_FCLK_ADDR (uint32_t *)0x60081EAC
|
||||
|
||||
/*
|
||||
* The system boot version is stored in the least significant 24 bits of a word.
|
||||
* The FCLK is stored in eNVM from version 1.3.1 of the system boot. We expect
|
||||
* that the major version number of the system boot version will change if the
|
||||
* system boot configuration data layout needs to change.
|
||||
*/
|
||||
#define SYSBOOT_VERSION_MASK 0x00FFFFFFuL
|
||||
#define MIN_SYSBOOT_VERSION 0x00010301uL
|
||||
#define SYSBOOT_VERSION_2_X 0x00020000uL
|
||||
#define MAX_SYSBOOT_VERSION 0x00030000uL
|
||||
|
||||
/* Standard CMSIS global variables. */
|
||||
uint32_t SystemFrequency = SMARTFUSION_FCLK_FREQ; /*!< System Clock Frequency (Core Clock) */
|
||||
uint32_t SystemCoreClock = SMARTFUSION_FCLK_FREQ; /*!< System Clock Frequency (Core Clock) */
|
||||
|
||||
/* SmartFusion specific clocks. */
|
||||
uint32_t g_FrequencyPCLK0 = (SMARTFUSION_FCLK_FREQ / RESET_PCLK0_DIV); /*!< Clock frequency of APB bus 0. */
|
||||
uint32_t g_FrequencyPCLK1 = (SMARTFUSION_FCLK_FREQ / RESET_PCLK1_DIV); /*!< Clock frequency of APB bus 1. */
|
||||
uint32_t g_FrequencyACE = (SMARTFUSION_FCLK_FREQ / RESET_ACE_DIV); /*!< Clock frequency of Analog Compute Engine. */
|
||||
uint32_t g_FrequencyFPGA = (SMARTFUSION_FCLK_FREQ / RESET_FPGA_CLK_DIV); /*!< Clock frequecny of FPGA fabric */
|
||||
|
||||
/* Local functions */
|
||||
static uint32_t GetSystemClock( void );
|
||||
|
||||
/***************************************************************************//**
|
||||
* See system_a2fm3fxxx.h for details.
|
||||
*/
|
||||
void SystemInit(void)
|
||||
{
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
*
|
||||
*/
|
||||
void SystemCoreClockUpdate (void)
|
||||
{
|
||||
uint32_t PclkDiv0;
|
||||
uint32_t PclkDiv1;
|
||||
uint32_t AceDiv;
|
||||
uint32_t FabDiv;
|
||||
|
||||
const uint32_t pclk_div_lut[4] = { 1uL, 2uL, 4uL, 1uL };
|
||||
|
||||
/* Read PCLK dividers from system registers. Multiply the value read from
|
||||
* system register by two to get actual divider value. */
|
||||
PclkDiv0 = pclk_div_lut[((SYSREG->MSS_CLK_CR >> PCLK0_DIV_SHIFT) & PCLK_DIV_MASK)];
|
||||
PclkDiv1 = pclk_div_lut[((SYSREG->MSS_CLK_CR >> PCLK1_DIV_SHIFT) & PCLK_DIV_MASK)];
|
||||
AceDiv = pclk_div_lut[((SYSREG->MSS_CLK_CR >> ACE_DIV_SHIFT) & PCLK_DIV_MASK)];
|
||||
{
|
||||
/* Compute the FPGA fabric frequency divider. */
|
||||
uint32_t obdiv;
|
||||
uint32_t obdivhalf;
|
||||
|
||||
obdiv = (SYSREG->MSS_CCC_DIV_CR >> OBDIV_SHIFT) & OBDIV_MASK;
|
||||
obdivhalf = (SYSREG->MSS_CCC_DIV_CR >> OBDIVHALF_SHIFT) & OBDIVHALF_MASK;
|
||||
FabDiv = obdiv + 1uL;
|
||||
if ( obdivhalf != 0uL )
|
||||
{
|
||||
FabDiv = FabDiv * 2uL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieve FCLK from eNVM spare pages if Actel system boot programmed as part of the system. */
|
||||
|
||||
/* Read system clock from eNVM spare pages. */
|
||||
SystemCoreClock = GetSystemClock();
|
||||
g_FrequencyPCLK0 = SystemCoreClock / PclkDiv0;
|
||||
g_FrequencyPCLK1 = SystemCoreClock / PclkDiv1;
|
||||
g_FrequencyACE = SystemCoreClock / AceDiv;
|
||||
g_FrequencyFPGA = SystemCoreClock / FabDiv;
|
||||
|
||||
/* Keep SystemFrequency as well as SystemCoreClock for legacy reasons. */
|
||||
SystemFrequency = SystemCoreClock;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Retrieve the system clock frequency from eNVM spare page if available.
|
||||
* Returns the frequency defined through SMARTFUSION_FCLK_FREQ if FCLK cannot be
|
||||
* retrieved from eNVM spare pages.
|
||||
* The FCLK frequency value selected in the MSS Configurator software tool is
|
||||
* stored in eNVM spare pages as part of the Actel system boot configuration data.
|
||||
*/
|
||||
uint32_t GetSystemClock( void )
|
||||
{
|
||||
uint32_t fclk = 0uL;
|
||||
|
||||
uint32_t * p_sysboot_key = SYSBOOT_KEY_ADDR;
|
||||
|
||||
if ( SYSBOOT_KEY_VALUE == *p_sysboot_key )
|
||||
{
|
||||
/* Actel system boot programmed, check if it has the FCLK value stored. */
|
||||
uint32_t *p_sysboot_version = SYSBOOT_VERSION_ADDR;
|
||||
uint32_t sysboot_version = *p_sysboot_version;
|
||||
|
||||
sysboot_version &= SYSBOOT_VERSION_MASK;
|
||||
|
||||
if ( sysboot_version >= MIN_SYSBOOT_VERSION )
|
||||
{
|
||||
/* Handle change of eNVM location of FCLK between 1.3.x and 2.x.x versions of the system boot. */
|
||||
if ( sysboot_version < SYSBOOT_VERSION_2_X )
|
||||
{
|
||||
/* Read FCLK value from MSS configurator generated configuration
|
||||
* data stored in eNVM spare pages as part of system boot version 1.3.x
|
||||
* configuration tables. */
|
||||
uint32_t *p_fclk = SYSBOOT_1_3_FCLK_ADDR;
|
||||
fclk = *p_fclk;
|
||||
}
|
||||
else if ( sysboot_version < MAX_SYSBOOT_VERSION )
|
||||
{
|
||||
/* Read FCLK value from MSS configurator generated configuration
|
||||
* data stored in eNVM spare pages as part of system boot version 2.x.x
|
||||
* configuration tables. */
|
||||
uint32_t *p_fclk = SYSBOOT_2_x_FCLK_ADDR;
|
||||
fclk = *p_fclk;
|
||||
}
|
||||
else
|
||||
{
|
||||
fclk = 0uL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0uL == fclk )
|
||||
{
|
||||
/*
|
||||
* Could not retrieve FCLK from system boot configuration data. Fall back
|
||||
* to using SMARTFUSION_FCLK_FREQ which must then be defined as part of
|
||||
* project settings.
|
||||
*/
|
||||
ASSERT( SMARTFUSION_FCLK_FREQ_DEFINED );
|
||||
fclk = SMARTFUSION_FCLK_FREQ;
|
||||
}
|
||||
|
||||
return fclk;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion A2FxxxM3 CMSIS system initialization.
|
||||
*
|
||||
* SVN $Revision: 2064 $
|
||||
* SVN $Date: 2010-01-27 15:05:58 +0000 (Wed, 27 Jan 2010) $
|
||||
*/
|
||||
|
||||
#ifndef __SYSTEM_A2FM3FXX_H__
|
||||
#define __SYSTEM_A2FM3FXX_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Standard CMSIS global variables. */
|
||||
extern uint32_t SystemFrequency; /*!< System Clock Frequency (Core Clock) */
|
||||
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
|
||||
|
||||
/* SmartFusion specific clocks. */
|
||||
extern uint32_t g_FrequencyPCLK0; /*!< Clock frequency of APB bus 0. */
|
||||
extern uint32_t g_FrequencyPCLK1; /*!< Clock frequency of APB bus 1. */
|
||||
extern uint32_t g_FrequencyACE; /*!< Clock frequency of Analog Compute Engine. */
|
||||
extern uint32_t g_FrequencyFPGA; /*!< Clock frequecny of FPGA fabric */
|
||||
|
||||
/***************************************************************************//**
|
||||
* The SystemInit() is a standard CMSIS function called during system startup.
|
||||
* It is meant to perform low level hardware setup such as configuring PLLs. In
|
||||
* the case of SmartFusion these hardware setup operations are performed by the
|
||||
* chip boot which executed before the application started. Therefore this
|
||||
* function does not need to perform any hardware setup.
|
||||
*/
|
||||
void SystemInit(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* The SystemCoreClockUpdate() is a standard CMSIS function which can be called
|
||||
* by the application in order to ensure that the SystemCoreClock global
|
||||
* variable contains the up to date Cortex-M3 core frequency. Calling this
|
||||
* function also updates the global variables containing the frequencies of the
|
||||
* APB busses connecting the peripherals and the ACE frequency.
|
||||
*/
|
||||
void SystemCoreClockUpdate(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
798
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/drivers/I2C/i2c.c
Normal file
798
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/drivers/I2C/i2c.c
Normal file
|
@ -0,0 +1,798 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2007-2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion microcontroller subsystem I2C bare metal software driver
|
||||
* implementation.
|
||||
*
|
||||
* SVN $Revision: 2152 $
|
||||
* SVN $Date: 2010-02-11 14:44:11 +0000 (Thu, 11 Feb 2010) $
|
||||
*/
|
||||
#include "i2c.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* I2C transaction direction.
|
||||
*/
|
||||
#define WRITE_DIR 0
|
||||
#define READ_DIR 1
|
||||
|
||||
/* -- TRANSACTIONS TYPES -- */
|
||||
#define NO_TRANSACTION 0
|
||||
#define MASTER_WRITE_TRANSACTION 1
|
||||
#define MASTER_READ_TRANSACTION 2
|
||||
#define MASTER_RANDOM_READ_TRANSACTION 3
|
||||
#define WRITE_SLAVE_TRANSACTION 4
|
||||
#define READ_SLAVE_TRANSACTION 5
|
||||
#define RANDOM_READ_SLAVE_TRANSACTION 6
|
||||
|
||||
|
||||
/* -- SMBUS H/W STATES -- */
|
||||
/* -- MASTER STATES -- */
|
||||
#define ST_START 0x08 /* start condition sent */
|
||||
#define ST_RESTART 0x10 /* repeated start */
|
||||
#define ST_SLAW_ACK 0x18 /* SLA+W sent, ack received */
|
||||
#define ST_SLAW_NACK 0x20 /* SLA+W sent, nack received */
|
||||
#define ST_TX_DATA_ACK 0x28 /* Data sent, ACK'ed */
|
||||
#define ST_TX_DATA_NACK 0x30 /* Data sent, NACK'ed */
|
||||
#define ST_LOST_ARB 0x38 /* Master lost arbitration */
|
||||
#define ST_SLAR_ACK 0x40 /* SLA+R sent, ACK'ed */
|
||||
#define ST_SLAR_NACK 0x48 /* SLA+R sent, NACK'ed */
|
||||
#define ST_RX_DATA_ACK 0x50 /* Data received, ACK sent */
|
||||
#define ST_RX_DATA_NACK 0x58 /* Data received, NACK sent */
|
||||
|
||||
/* -- SLAVE STATES -- */
|
||||
#define ST_SLAVE_SLAW 0x60 /* SLA+W received */
|
||||
#define ST_SLAVE_SLAR_ACK 0xA8 /* SLA+R received, ACK returned */
|
||||
#define ST_SLV_LA 0x68 /* Slave lost arbitration */
|
||||
#define ST_GCA 0x70 /* GCA received */
|
||||
#define ST_GCA_LA 0x78 /* GCA lost arbitration */
|
||||
#define ST_RDATA 0x80 /* Data received */
|
||||
#define ST_SLA_NACK 0x88 /* Slave addressed, NACK returned */
|
||||
#define ST_GCA_ACK 0x90 /* Previously addresses with GCA, data ACKed */
|
||||
#define ST_GCA_NACK 0x98 /* GCA addressed, NACK returned */
|
||||
#define ST_RSTOP 0xA0 /* Stop received */
|
||||
#define ST_REPEAT 0xA0 /* Repeated start received */
|
||||
#define ST_SLAR_ACKS 0xA8 /* Slave read received, ACKed */
|
||||
#define ST_SLARW_LA 0xB0 /* Arbitration lost */
|
||||
#define ST_RACK 0xB8 /* Byte sent, ACK received */
|
||||
#define ST_SLAVE_RNACK 0xC0 /* Byte sent, NACK received */
|
||||
#define ST_FINAL 0xC8 /* Final byte sent, ACK received */
|
||||
#define ST_BERR 0x00 /* Error on the bus */
|
||||
#define ST_SLV_RST 0xD8 /* Slave reset state */
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
static uint32_t disable_interrupts( void );
|
||||
static void restore_interrupts( uint32_t primask );
|
||||
static void mss_i2c_isr( mss_i2c_instance_t * this_i2c );
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
*------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
mss_i2c_instance_t g_mss_i2c0;
|
||||
mss_i2c_instance_t g_mss_i2c1;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_init()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_I2C_init
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t ser_address,
|
||||
mss_i2c_clock_divider_t ser_clock_speed
|
||||
)
|
||||
{
|
||||
uint_fast16_t clock_speed = ser_clock_speed;
|
||||
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
if ( this_i2c == &g_mss_i2c0 )
|
||||
{
|
||||
this_i2c->irqn = I2C0_IRQn;
|
||||
this_i2c->hw_reg = I2C0;
|
||||
this_i2c->hw_reg_bit = I2C0_BITBAND;
|
||||
|
||||
/* reset I2C0 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_I2C0_SOFTRESET_MASK;
|
||||
/* Clear any previously pended I2C0 interrupt */
|
||||
NVIC_ClearPendingIRQ( I2C0_IRQn );
|
||||
/* Take I2C0 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_I2C0_SOFTRESET_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_i2c->irqn = I2C1_IRQn;
|
||||
this_i2c->hw_reg = I2C1;
|
||||
this_i2c->hw_reg_bit = I2C1_BITBAND;
|
||||
|
||||
/* reset I2C1 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_I2C1_SOFTRESET_MASK;
|
||||
/* Clear any previously pended I2C1 interrupt */
|
||||
NVIC_ClearPendingIRQ( I2C1_IRQn );
|
||||
/* Take I2C1 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_I2C1_SOFTRESET_MASK;
|
||||
}
|
||||
|
||||
this_i2c->transaction = NO_TRANSACTION;
|
||||
|
||||
this_i2c->ser_address = ser_address;
|
||||
|
||||
this_i2c->tx_buffer = 0;
|
||||
this_i2c->tx_size = 0;
|
||||
this_i2c->tx_idx = 0;
|
||||
|
||||
this_i2c->rx_buffer = 0;
|
||||
this_i2c->rx_size = 0;
|
||||
this_i2c->rx_idx = 0;
|
||||
|
||||
this_i2c->status = MSS_I2C_SUCCESS;
|
||||
|
||||
this_i2c->random_read_addr = 0;
|
||||
|
||||
this_i2c->slave_write_handler = 0;
|
||||
this_i2c->slave_mem_offset_length = 0;
|
||||
|
||||
this_i2c->hw_reg_bit->CTRL_ENS1 = 0x01; /* set enable bit */
|
||||
this_i2c->hw_reg_bit->CTRL_CR2 = (clock_speed >> 2) & 0x01;
|
||||
this_i2c->hw_reg_bit->CTRL_CR1 = (clock_speed >> 1) & 0x01;
|
||||
this_i2c->hw_reg_bit->CTRL_CR0 = clock_speed & 0x01;
|
||||
this_i2c->hw_reg->ADDR = this_i2c->ser_address;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_set_slave_mem_offset_length()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_I2C_set_slave_mem_offset_length
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t offset_length
|
||||
)
|
||||
{
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
this_i2c->slave_mem_offset_length = offset_length;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_register_write_handler()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_I2C_register_write_handler
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
mss_i2c_slave_wr_handler_t handler
|
||||
)
|
||||
{
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
this_i2c->slave_write_handler = handler;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_write()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_I2C_write
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t serial_addr,
|
||||
const uint8_t * write_buffer,
|
||||
uint16_t write_size,
|
||||
uint8_t options
|
||||
)
|
||||
{
|
||||
volatile uint8_t stat_ctrl;
|
||||
uint8_t serial_interrupt;
|
||||
|
||||
uint32_t primask;
|
||||
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
primask = disable_interrupts();
|
||||
|
||||
this_i2c->transaction = MASTER_WRITE_TRANSACTION;
|
||||
|
||||
this_i2c->target_addr = serial_addr;
|
||||
this_i2c->dir = WRITE_DIR;
|
||||
this_i2c->tx_buffer = write_buffer;
|
||||
this_i2c->tx_size = write_size;
|
||||
this_i2c->tx_idx = 0;
|
||||
|
||||
this_i2c->status = MSS_I2C_IN_PROGRESS;
|
||||
this_i2c->options = options;
|
||||
|
||||
/* Clear interrupts if required (depends on repeated starts).*/
|
||||
serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;
|
||||
this_i2c->hw_reg_bit->CTRL_STA = 0x01;
|
||||
|
||||
if ( serial_interrupt != 0 )
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_SI = 0x00;
|
||||
NVIC_ClearPendingIRQ( this_i2c->irqn );
|
||||
}
|
||||
|
||||
stat_ctrl = this_i2c->hw_reg->STATUS;
|
||||
|
||||
NVIC_EnableIRQ( this_i2c->irqn );
|
||||
|
||||
restore_interrupts( primask );
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_read()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_I2C_read
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t serial_addr,
|
||||
uint8_t * read_buffer,
|
||||
uint16_t read_size,
|
||||
uint8_t options
|
||||
)
|
||||
{
|
||||
uint32_t primask;
|
||||
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
if ( read_size > 0 )
|
||||
{
|
||||
volatile uint8_t stat_ctrl;
|
||||
uint8_t serial_interrupt;
|
||||
|
||||
primask = disable_interrupts();
|
||||
|
||||
this_i2c->transaction = MASTER_READ_TRANSACTION;
|
||||
|
||||
this_i2c->target_addr = serial_addr;
|
||||
this_i2c->dir = READ_DIR;
|
||||
this_i2c->rx_buffer = read_buffer;
|
||||
this_i2c->rx_size = read_size;
|
||||
this_i2c->rx_idx = 0;
|
||||
|
||||
this_i2c->status = MSS_I2C_IN_PROGRESS;
|
||||
|
||||
this_i2c->options = options;
|
||||
|
||||
/* Clear interrupts if required (depends on repeated starts).*/
|
||||
serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;
|
||||
this_i2c->hw_reg_bit->CTRL_STA = 0x01;
|
||||
|
||||
if ( serial_interrupt != 0 )
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_SI = 0x00;
|
||||
NVIC_ClearPendingIRQ( this_i2c->irqn );
|
||||
}
|
||||
|
||||
stat_ctrl = this_i2c->hw_reg->STATUS;
|
||||
|
||||
NVIC_EnableIRQ( this_i2c->irqn );
|
||||
|
||||
restore_interrupts( primask );
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_write_read()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_I2C_write_read
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t serial_addr,
|
||||
const uint8_t * addr_offset,
|
||||
uint16_t offset_size,
|
||||
uint8_t * read_buffer,
|
||||
uint16_t read_size,
|
||||
uint8_t options
|
||||
)
|
||||
{
|
||||
volatile uint8_t stat_ctrl;
|
||||
uint8_t serial_interrupt;
|
||||
uint32_t primask;
|
||||
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
primask = disable_interrupts();
|
||||
|
||||
this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION;
|
||||
this_i2c->target_addr = serial_addr;
|
||||
this_i2c->dir = WRITE_DIR;
|
||||
this_i2c->tx_buffer = addr_offset;
|
||||
this_i2c->tx_size = offset_size;
|
||||
this_i2c->tx_idx = 0;
|
||||
|
||||
this_i2c->rx_buffer = read_buffer;
|
||||
this_i2c->rx_size = read_size;
|
||||
this_i2c->rx_idx = 0;
|
||||
|
||||
this_i2c->status = MSS_I2C_IN_PROGRESS;
|
||||
this_i2c->options = options;
|
||||
|
||||
/* Clear interrupts if required (depends on repeated starts).*/
|
||||
serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;
|
||||
this_i2c->hw_reg_bit->CTRL_STA = 0x01;
|
||||
|
||||
if ( serial_interrupt != 0 )
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_SI = 0x00;
|
||||
NVIC_ClearPendingIRQ( this_i2c->irqn );
|
||||
}
|
||||
|
||||
stat_ctrl = this_i2c->hw_reg->STATUS;
|
||||
|
||||
NVIC_EnableIRQ( this_i2c->irqn );
|
||||
|
||||
restore_interrupts( primask );
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_set_slave_rx_buffer()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_I2C_set_slave_rx_buffer
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t * rx_buffer,
|
||||
uint16_t rx_size
|
||||
)
|
||||
{
|
||||
uint32_t primask;
|
||||
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
primask = disable_interrupts();
|
||||
|
||||
this_i2c->rx_buffer = rx_buffer;
|
||||
this_i2c->rx_size = rx_size;
|
||||
this_i2c->rx_idx = 0;
|
||||
|
||||
restore_interrupts( primask );
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_get_status()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
mss_i2c_status_t MSS_I2C_get_status
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c
|
||||
)
|
||||
{
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
return this_i2c->status;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_set_slave_tx_buffer()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_I2C_set_slave_tx_buffer
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t * tx_buffer,
|
||||
uint16_t tx_size
|
||||
)
|
||||
{
|
||||
uint32_t primask;
|
||||
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
primask = disable_interrupts();
|
||||
|
||||
this_i2c->tx_buffer = tx_buffer;
|
||||
this_i2c->tx_size = tx_size;
|
||||
this_i2c->tx_idx = 0;
|
||||
|
||||
restore_interrupts( primask );
|
||||
|
||||
/* Set the assert acknowledge bit. */
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x01;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_enable_slave_rx()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_I2C_enable_slave_rx
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c
|
||||
)
|
||||
{
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
/* Set the assert acknowledge bit. */
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x01;
|
||||
/* accept GC addressing. */
|
||||
this_i2c->hw_reg_bit->ADDR_GC = 0x01;
|
||||
|
||||
NVIC_EnableIRQ( this_i2c->irqn );
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS_I2C_wait_complete()
|
||||
* See "mss_i2c.h" for details of how to use this function.
|
||||
*/
|
||||
mss_i2c_status_t MSS_I2C_wait_complete
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c
|
||||
)
|
||||
{
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
while ( this_i2c->status == MSS_I2C_IN_PROGRESS )
|
||||
{
|
||||
/* Wait for transaction to compltete.*/
|
||||
;
|
||||
}
|
||||
return this_i2c->status;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* MSS I2C interrupt service routine.
|
||||
*------------------------------------------------------------------------------
|
||||
* Parameters:
|
||||
*
|
||||
* mss_i2c_instance_t * this_i2c:
|
||||
* Pointer to the mss_i2c_instance_t data structure holding all data related to
|
||||
* the MSS I2C instance that generated the interrupt.
|
||||
*/
|
||||
static void mss_i2c_isr
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c
|
||||
)
|
||||
{
|
||||
volatile uint8_t status;
|
||||
uint8_t data;
|
||||
uint8_t hold_bus;
|
||||
uint8_t clear_irq = 1;
|
||||
|
||||
ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
|
||||
|
||||
status = this_i2c->hw_reg->STATUS;
|
||||
|
||||
switch( status )
|
||||
{
|
||||
/************** MASTER TRANSMITTER / RECEIVER *******************/
|
||||
|
||||
case ST_START: /* start has been xmt'd */
|
||||
case ST_RESTART: /* repeated start has been xmt'd */
|
||||
this_i2c->hw_reg_bit->CTRL_STA = 0x0;
|
||||
this_i2c->hw_reg->DATA = this_i2c->target_addr;
|
||||
this_i2c->hw_reg_bit->DATA_DIR = this_i2c->dir;
|
||||
|
||||
this_i2c->tx_idx = 0;
|
||||
this_i2c->rx_idx = 0;
|
||||
break;
|
||||
|
||||
case ST_LOST_ARB:
|
||||
/* Set start bit. Let's keep trying! Don't give up! */
|
||||
this_i2c->hw_reg_bit->CTRL_STA = 0x01;
|
||||
break;
|
||||
|
||||
/******************* MASTER TRANSMITTER *************************/
|
||||
case ST_SLAW_ACK:
|
||||
/* call address has been xmt'd with ACK, time to send data byte and increment index. */
|
||||
if ( this_i2c->tx_idx < this_i2c->tx_size )
|
||||
{
|
||||
/* load data byte */
|
||||
this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
|
||||
}
|
||||
else
|
||||
{
|
||||
NVIC_DisableIRQ( this_i2c->irqn );
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_SLAW_NACK:
|
||||
#if 0
|
||||
/* SLA+W has been transmitted; not ACK has been received - let's stop. */
|
||||
this_i2c->hw_reg_bit->CTRL_STO = 0x01;
|
||||
this_i2c->status = MSS_I2C_FAILED;
|
||||
#endif
|
||||
/* call address has been xmt'd with ACK, time to send data byte and increment index. */
|
||||
if ( this_i2c->tx_idx < this_i2c->tx_size )
|
||||
{
|
||||
/* load data byte */
|
||||
this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
|
||||
}
|
||||
else
|
||||
{
|
||||
NVIC_DisableIRQ( this_i2c->irqn );
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_TX_DATA_ACK:
|
||||
/* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */
|
||||
if (this_i2c->tx_idx < this_i2c->tx_size)
|
||||
{
|
||||
this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
|
||||
}
|
||||
else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION )
|
||||
{
|
||||
/* We are finished sending the address offset part of a random read transaction.
|
||||
* It is is time to send a restart in order to change direction. */
|
||||
this_i2c->dir = READ_DIR;
|
||||
this_i2c->hw_reg_bit->CTRL_STA = 0x01;
|
||||
}
|
||||
else /* done sending. let's stop */
|
||||
{
|
||||
hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;
|
||||
if ( hold_bus == 0 )
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */
|
||||
}
|
||||
else
|
||||
{
|
||||
NVIC_DisableIRQ( this_i2c->irqn );
|
||||
clear_irq = 0;
|
||||
}
|
||||
this_i2c->status = MSS_I2C_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_TX_DATA_NACK:
|
||||
#if 0
|
||||
/* data byte SENT, ACK to be received
|
||||
* In fact, this means we've received a NACK (This may not be
|
||||
* obvious, but if we've rec'd an ACK then we would be in state
|
||||
* 0x28!) hence, let's send a stop bit
|
||||
*/
|
||||
this_i2c->hw_reg_bit->CTRL_STO = 0x01;
|
||||
this_i2c->status = MSS_I2C_FAILED;
|
||||
#endif
|
||||
/* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */
|
||||
if (this_i2c->tx_idx < this_i2c->tx_size)
|
||||
{
|
||||
this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
|
||||
}
|
||||
else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION )
|
||||
{
|
||||
/* We are finished sending the address offset part of a random read transaction.
|
||||
* It is is time to send a restart in order to change direction. */
|
||||
this_i2c->dir = READ_DIR;
|
||||
this_i2c->hw_reg_bit->CTRL_STA = 0x01;
|
||||
}
|
||||
else /* done sending. let's stop */
|
||||
{
|
||||
hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;
|
||||
if ( hold_bus == 0 )
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */
|
||||
}
|
||||
else
|
||||
{
|
||||
NVIC_DisableIRQ( this_i2c->irqn );
|
||||
clear_irq = 0;
|
||||
}
|
||||
this_i2c->status = MSS_I2C_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
/********************* MASTER (or slave?) RECEIVER *************************/
|
||||
|
||||
/* STATUS codes 08H, 10H, 38H are all covered in MTX mode */
|
||||
case ST_SLAR_ACK: /* SLA+R tx'ed. */
|
||||
/* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless
|
||||
* the next byte is the last byte of the read transaction.
|
||||
*/
|
||||
if( this_i2c->rx_size > 1 )
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x00;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */
|
||||
this_i2c->hw_reg_bit->CTRL_STO = 0x01;
|
||||
this_i2c->status = MSS_I2C_FAILED;
|
||||
break;
|
||||
|
||||
case ST_RX_DATA_ACK: /* Data byte received, ACK returned */
|
||||
/* First, get the data */
|
||||
this_i2c->rx_buffer[this_i2c->rx_idx++] = this_i2c->hw_reg->DATA;
|
||||
|
||||
if( this_i2c->rx_idx >= this_i2c->rx_size - 1)
|
||||
{
|
||||
/* If we're at the second last byte, let's set AA to 0 so
|
||||
* we return a NACK at the last byte. */
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x00;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_RX_DATA_NACK: /* Data byte received, NACK returned */
|
||||
/* Get the data, then send a stop condition */
|
||||
this_i2c->rx_buffer[this_i2c->rx_idx++] = this_i2c->hw_reg->DATA;
|
||||
|
||||
hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;
|
||||
if ( hold_bus == 0 )
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */
|
||||
}
|
||||
else
|
||||
{
|
||||
NVIC_DisableIRQ( this_i2c->irqn );
|
||||
clear_irq = 0;
|
||||
}
|
||||
|
||||
this_i2c->status = MSS_I2C_SUCCESS;
|
||||
break;
|
||||
|
||||
/******************** SLAVE RECEIVER **************************/
|
||||
case ST_GCA_NACK: /* NACK after, GCA addressing */
|
||||
case ST_SLA_NACK: /* Get Data, but also re-enable AA (assert ack) bit for future transmissions */
|
||||
if ( this_i2c->rx_buffer != 0 )
|
||||
{
|
||||
this_i2c->rx_buffer[this_i2c->rx_idx] = this_i2c->hw_reg->DATA;
|
||||
}
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x01;
|
||||
break;
|
||||
|
||||
case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */
|
||||
this_i2c->transaction = WRITE_SLAVE_TRANSACTION;
|
||||
this_i2c->rx_idx = 0;
|
||||
this_i2c->random_read_addr = 0;
|
||||
#ifndef INCLUDE_SLA_IN_RX_PAYLOAD
|
||||
/* Only break from this case if the slave address must NOT be included at the
|
||||
* beginning of the received write data. */
|
||||
break;
|
||||
#endif
|
||||
case ST_GCA_ACK: /* DATA received; ACK sent after GCA */
|
||||
case ST_RDATA: /* DATA received; must clear DATA register */
|
||||
if (this_i2c->rx_idx >= this_i2c->rx_size - 2)
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x00; /* send a NACK when done (next reception) */
|
||||
}
|
||||
data = this_i2c->hw_reg->DATA;
|
||||
this_i2c->rx_buffer[this_i2c->rx_idx++] = data;
|
||||
this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data;
|
||||
|
||||
break;
|
||||
|
||||
case ST_RSTOP:
|
||||
/* STOP or repeated START occured. */
|
||||
/* We cannot be sure if the transaction has actually completed as
|
||||
* this hardware state reports that either a STOP or repeated START
|
||||
* condition has occured. We assume that this is a repeated START
|
||||
* if the transaction was a write from the master to this point.*/
|
||||
if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION )
|
||||
{
|
||||
if ( this_i2c->rx_idx == this_i2c->slave_mem_offset_length )
|
||||
{
|
||||
this_i2c->transaction = RANDOM_READ_SLAVE_TRANSACTION;
|
||||
this_i2c->tx_idx = this_i2c->random_read_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Call the slave's write transaction handler if it exists. */
|
||||
if ( this_i2c->slave_write_handler != 0 )
|
||||
{
|
||||
mss_i2c_slave_handler_ret_t h_ret;
|
||||
h_ret = this_i2c->slave_write_handler( this_i2c->rx_buffer, (uint16_t)this_i2c->rx_idx );
|
||||
if ( MSS_I2C_REENABLE_SLAVE_RX == h_ret )
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Mark any previous master write transaction as complete. */
|
||||
this_i2c->status = MSS_I2C_SUCCESS;
|
||||
break;
|
||||
|
||||
case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */
|
||||
case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */
|
||||
case ST_GCA: /* General call address received, ACK returned */
|
||||
case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */
|
||||
/* do nothing */
|
||||
break;
|
||||
|
||||
/****************** SLAVE TRANSMITTER **************************/
|
||||
case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */
|
||||
case ST_SLARW_LA: /* Arbitration lost, and: */
|
||||
case ST_RACK: /* Data tx'ed, ACK received */
|
||||
if ( status == ST_SLAVE_SLAR_ACK )
|
||||
{
|
||||
this_i2c->transaction = READ_SLAVE_TRANSACTION;
|
||||
this_i2c->random_read_addr = 0;
|
||||
}
|
||||
/* Load the data, and determine if it is the last one */
|
||||
this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
|
||||
if (this_i2c->tx_idx >= this_i2c->tx_size - 1) /* last byte? */
|
||||
{
|
||||
this_i2c->hw_reg_bit->CTRL_AA = 0x00;
|
||||
/* Next read transaction will result in slave's transmit buffer
|
||||
* being sent from the first byte. */
|
||||
this_i2c->tx_idx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */
|
||||
/* We assume that the transaction will be stopped by the master.
|
||||
* Reset tx_idx so that a subsequent read will result in the slave's
|
||||
* transmit buffer being sent from the first byte. */
|
||||
this_i2c->tx_idx = 0;
|
||||
break;
|
||||
|
||||
case ST_FINAL: /* Last Data byte tx'ed, ACK recieved */
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
if ( clear_irq )
|
||||
{
|
||||
/* clear interrupt. */
|
||||
this_i2c->hw_reg_bit->CTRL_SI = 0x00;
|
||||
}
|
||||
|
||||
/* Read the status register to ensure the last I2C registers write took place
|
||||
* in a system built around a bus making use of posted writes. */
|
||||
status = this_i2c->hw_reg->STATUS;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
uint32_t disable_interrupts( void )
|
||||
{
|
||||
uint32_t primask;
|
||||
primask = __get_PRIMASK();
|
||||
return primask;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
void restore_interrupts( uint32_t primask )
|
||||
{
|
||||
__set_PRIMASK( primask );
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void I2C0_IRQHandler( void )
|
||||
#else
|
||||
void I2C0_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
mss_i2c_isr( &g_mss_i2c0 );
|
||||
NVIC_ClearPendingIRQ( I2C0_IRQn );
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void I2C1_IRQHandler( void )
|
||||
#else
|
||||
void I2C1_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
mss_i2c_isr( &g_mss_i2c1 );
|
||||
NVIC_ClearPendingIRQ( I2C1_IRQn );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
775
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/drivers/I2C/i2c.h
Normal file
775
Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/drivers/I2C/i2c.h
Normal file
|
@ -0,0 +1,775 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2007-2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion microcontroller subsystem I2C bare metal software driver public
|
||||
* API.
|
||||
*
|
||||
* SVN $Revision: 2150 $
|
||||
* SVN $Date: 2010-02-11 14:39:24 +0000 (Thu, 11 Feb 2010) $
|
||||
*/
|
||||
/*=========================================================================*//**
|
||||
@mainpage SmartFusion MSS I2C Bare Metal Driver.
|
||||
|
||||
@section intro_sec Introduction
|
||||
The SmartFusion™ microcontroller subsystem (MSS) includes two I2C peripherals
|
||||
for serial communication. This driver provides a set of functions for
|
||||
controlling the MSS I2Cs as part of a bare metal system where no operating
|
||||
system is available. These drivers can be adapted for use as part of an
|
||||
operating system, but the implementation of the adaptation layer between this
|
||||
driver and the operating system's driver model is outside the scope of this
|
||||
driver.
|
||||
|
||||
@section hw_dependencies Hardware Flow Dependencies
|
||||
The configuration of all features of the MSS I2Cs is covered by this driver
|
||||
with the exception of the SmartFusion IOMUX configuration. SmartFusion allows
|
||||
multiple non-concurrent uses of some external pins through IOMUX configuration.
|
||||
This feature allows optimization of external pin usage by assigning external
|
||||
pins for use by either the microcontroller subsystem or the FPGA fabric. The
|
||||
MSS I2Cs serial signals are routed through IOMUXes to the SmartFusion device
|
||||
external pins. These IOMUXes are automatically configured correctly by the MSS
|
||||
configurator tool in the hardware flow when the MSS I2Cs are enabled in that
|
||||
tool. You must ensure that the MSS I2Cs are enabled by the MSS configurator
|
||||
tool in the hardware flow; otherwise the serial inputs and outputs will not be
|
||||
connected to the chip's external pins. For more information on IOMUX, refer to
|
||||
the IOMUX section of the SmartFusion Datasheet.
|
||||
The base address, register addresses and interrupt number assignment for the
|
||||
MSS I2C blocks are defined as constants in the SmartFusion CMSIS-PAL. You must
|
||||
ensure that the SmartFusion CMSIS-PAL is either included in the software tool
|
||||
chain used to build your project or is included in your project.
|
||||
|
||||
@section theory_op Theory of Operation
|
||||
The MSS I2C driver functions are grouped into the following categories:
|
||||
• Initialization and configuration functions
|
||||
• Interrupt control
|
||||
• I2C master operations – functions to handle write, read and write-read transactions
|
||||
• I2C slave operations – functions to handle write, read and write-read transactions
|
||||
|
||||
Initialization and Configuration
|
||||
The MSS I2C driver is initialized through a call to the MSS_I2C_init()
|
||||
function. This function takes the MSS I2C's configuration as parameters. The
|
||||
MSS_I2C_init() function must be called before any other MSS I2C driver
|
||||
functions can be called. The first parameter of the MSS_I2C_init() function
|
||||
is a pointer to one of two global data structures used by the driver to
|
||||
store state information for each MSS I2C. A pointer to these data structures
|
||||
is also used as first parameter to any of the driver functions to identify
|
||||
which MSS I2C will be used by the called function. The names of these two
|
||||
data structures are g_mss_i2c0 and g_mss_i2c1. Therefore any call to an MSS
|
||||
I2C driver function should be of the form MSS_I2C_function_name( &g_mss_i2c0, ... )
|
||||
or MSS_I2C_function_name( &g_mss_i2c1, ... ).
|
||||
The MSS_I2C_init() function call for each MSS I2C also takes the I2C serial
|
||||
address assigned to the MSS I2C and the serial clock divider to be used to
|
||||
generate its I2C clock as configuration parameters.
|
||||
|
||||
Interrupt Control
|
||||
The MSS I2C driver is interrupt driven and it enables and disables the
|
||||
generation of interrupts by MSS I2C at various times when it is operating.
|
||||
The driver automatically handles MSS I2C interrupts internally, including
|
||||
enabling disabling and clearing MSS I2C interrupts in the Cortex-M3
|
||||
interrupt controller when required.
|
||||
The function MSS_I2C_register_write_handler() is used to register a write
|
||||
handler function with the MSS I2C driver that it will call on completion of
|
||||
an I2C write transaction by the MSS I2C slave. It is your responsibility to
|
||||
create and register the implementation of this handler function that will
|
||||
process or trigger the processing of the received data.
|
||||
Transaction Types
|
||||
The MSS I2C driver is designed to handle three types of I2C transaction:
|
||||
• Write transactions
|
||||
• Read transactions
|
||||
• Write-read transactions
|
||||
|
||||
Write transaction
|
||||
The master I2C device initiates a write transaction by sending a START bit
|
||||
as soon as the bus becomes free. The START bit is followed by the 7-bit
|
||||
serial address of the target slave device followed by the read/write bit
|
||||
indicating the direction of the transaction. The slave acknowledges receipt
|
||||
of it’s address with an acknowledge bit. The master sends data one byte at
|
||||
a time to the slave, which must acknowledge receipt of each byte for the
|
||||
next byte to be sent. The master sends a STOP bit to complete the transaction.
|
||||
The slave can abort the transaction by replying with a non-acknowledge bit
|
||||
instead of an acknowledge.
|
||||
The application programmer can choose not to send a STOP bit at the end of
|
||||
the transaction causing the next transaction to begin with a repeated START bit.
|
||||
|
||||
Read transaction
|
||||
The master I2C device initiates a read transaction by sending a START bit
|
||||
as soon as the bus becomes free. The START bit is followed by the 7-bit
|
||||
serial address of the target slave device followed by the read/write bit
|
||||
indicating the direction of the transaction. The slave acknowledges receipt
|
||||
of it’s slave address with an acknowledge bit. The slave sends data one byte
|
||||
at a time to the master, which must acknowledge receipt of each byte for the
|
||||
next byte to be sent. The master sends a non-acknowledge bit following the
|
||||
last byte it wishes to read followed by a STOP bit.
|
||||
The application programmer can choose not to send a STOP bit at the end of
|
||||
the transaction causing the next transaction to begin with a repeated START bit.
|
||||
|
||||
Write-read transaction
|
||||
The write-read transaction is a combination of a write transaction
|
||||
immediately followed by a read transaction. There is no STOP bit between
|
||||
the write and read phases of a write-read transaction. A repeated START
|
||||
bit is sent between the write and read phases.
|
||||
The write-read transaction is typically used to send a command or offset
|
||||
in the write transaction specifying the logical data to be transferred
|
||||
during the read phase.
|
||||
The application programmer can choose not to send a STOP bit at the end of
|
||||
the transaction causing the next transaction to begin with a repeated START bit.
|
||||
|
||||
Master Operations
|
||||
The application can use the MSS_I2C_write(), MSS_I2C_read() and MSS_I2C_write_read()
|
||||
functions to initiate an I2C bus transaction. The application can then wait
|
||||
for the transaction to complete using the MSS_I2C_wait_complete() function
|
||||
or poll the status of the I2C transaction using the MSS_I2C_get_status()
|
||||
function until it returns a value different from MSS_I2C_IN_PROGRESS.
|
||||
|
||||
Slave Operations
|
||||
The configuration of the MSS I2C driver to operate as an I2C slave requires
|
||||
the use of the following functions:
|
||||
• MSS_I2C_set_slave_tx_buffer()
|
||||
• MSS_I2C_set_slave_rx_buffer()
|
||||
• MSS_I2C_set_slave_mem_offset_length()
|
||||
• MSS_I2C_register_write_handler()
|
||||
• MSS_I2C_enable_slave_rx()
|
||||
Use of all functions is not required if the slave I2C does not need to support
|
||||
all types of I2C read transactions. The subsequent sections list the functions
|
||||
that must be used to support each transaction type.
|
||||
|
||||
Responding to read transactions
|
||||
The following functions are used to configure the MSS I2C driver to respond
|
||||
to I2C read transactions:
|
||||
• MSS_I2C_set_slave_tx_buffer()
|
||||
• MSS_I2C_enable_slave_rx()
|
||||
The function MSS_I2C_set_slave_tx_buffer() specifies the data buffer that
|
||||
will be transmitted when the I2C slave is the target of an I2C read
|
||||
transaction. It is then up to the application to manage the content of that
|
||||
buffer to control the data that will be transmitted to the I2C master as a
|
||||
result of the read transaction.
|
||||
The function MSS_I2C_enable_slave_rx() enables the MSS I2C hardware instance
|
||||
to respond to I2C transactions. It must be called after the MSS I2C driver
|
||||
has been configured to respond to the required transaction types.
|
||||
|
||||
Responding to write transactions
|
||||
The following functions are used to configure the MSS I2C driver to respond
|
||||
to I2C write transactions:
|
||||
• MSS_I2C_set_slave_rx_buffer()
|
||||
• MSS_I2C_register_write_handler()
|
||||
• MSS_I2C_enable_slave_rx()
|
||||
The function MSS_I2C_set_slave_rx_buffer() specifies the data buffer that
|
||||
will be used to store the data received by the I2C slave when it is the
|
||||
target an I2C write transaction.
|
||||
The function MSS_I2C_register_write_handler() specifies the handler function
|
||||
that must be called on completion of the I2C write transaction. It is this
|
||||
handler function that will process or trigger the processing of the received
|
||||
data.
|
||||
The function MSS_I2C_enable_slave_rx() enables the MSS I2C hardware instance
|
||||
to respond to I2C transactions. It must be called after the MSS I2C driver
|
||||
has been configured to respond to the required transaction types.
|
||||
|
||||
Responding to write-read transactions
|
||||
The following functions are used to configure the MSS I2C driver to respond
|
||||
to write-read transactions:
|
||||
• MSS_I2C_set_slave_tx_buffer()
|
||||
• MSS_I2C_set_slave_rx_buffer()
|
||||
• MSS_I2C_set_slave_mem_offset_length()
|
||||
• MSS_I2C_enable_slave_rx()
|
||||
The function MSS_I2C_set_slave_mem_offset_length() specifies the number of
|
||||
bytes expected by the I2C slave during the write phase of the write-read
|
||||
transaction.
|
||||
The function MSS_I2C_set_slave_tx_buffer() specifies the data that will be
|
||||
transmitted to the I2C master during the read phase of the write-read
|
||||
transaction. The value received by the I2C slave during the write phase of
|
||||
the transaction will be used as an index into the transmit buffer specified
|
||||
by this function to decide which part of the transmit buffer will be
|
||||
transmitted to the I2C master as part of the read phase of the write-read
|
||||
transaction.
|
||||
The function MSS_I2C_set_slave_rx_buffer() specifies the data buffer that
|
||||
will be used to store the data received by the I2C slave during the write
|
||||
phase of the write-read transaction. This buffer must be at least large
|
||||
enough to accommodate the number of bytes specified through the
|
||||
MSS_I2C_set_slave_mem_offset_length() function.
|
||||
The function MSS_I2C_enable_slave_rx() enables the MSS I2C hardware
|
||||
instance to respond to I2C transactions. It must be called after the MSS
|
||||
I2C driver has been configured to respond to the required transaction types.
|
||||
*//*=========================================================================*/
|
||||
#ifndef I2C_H_
|
||||
#define I2C_H_
|
||||
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The mss_i2c_clock_divider_t type is used to specify the divider to be applied
|
||||
to the MSS I2C BCLK signal in order to generate the I2C clock.
|
||||
*/
|
||||
typedef enum mss_i2c_clock_divider {
|
||||
MSS_I2C_PCLK_DIV_256 = 0,
|
||||
MSS_I2C_PCLK_DIV_224,
|
||||
MSS_I2C_PCLK_DIV_192,
|
||||
MSS_I2C_PCLK_DIV_160,
|
||||
MSS_I2C_PCLK_DIV_960,
|
||||
MSS_I2C_PCLK_DIV_120,
|
||||
MSS_I2C_PCLK_DIV_60,
|
||||
MSS_I2C_BCLK_DIV_8
|
||||
} mss_i2c_clock_divider_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_I2C_RELEASE_BUS constant is used to specify the options parameter to
|
||||
functions MSS_I2C_read(), MSS_I2C_write() and MSS_I2C_write_read() to indicate
|
||||
that a STOP bit must be generated at the end of the I2C transaction to release
|
||||
the bus.
|
||||
*/
|
||||
#define MSS_I2C_RELEASE_BUS 0x00
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_I2C_HOLD_BUS constant is used to specify the options parameter to
|
||||
functions MSS_I2C_read(), MSS_I2C_write() and MSS_I2C_write_read() to indicate
|
||||
that a STOP bit must not be generated at the end of the I2C transaction in
|
||||
order to retain the bus ownership. This will cause the next transaction to
|
||||
begin with a repeated START bit and no STOP bit between the transactions.
|
||||
*/
|
||||
#define MSS_I2C_HOLD_BUS 0x01
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The mss_i2c_status_t type is used to report the status of I2C transactions.
|
||||
*/
|
||||
typedef enum mss_i2c_status
|
||||
{
|
||||
MSS_I2C_SUCCESS = 0,
|
||||
MSS_I2C_IN_PROGRESS,
|
||||
MSS_I2C_FAILED
|
||||
} mss_i2c_status_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The mss_i2c_slave_handler_ret_t type is used by slave write handler functions
|
||||
to indicate whether the received data buffer should be released or not.
|
||||
*/
|
||||
typedef enum mss_i2c_slave_handler_ret {
|
||||
MSS_I2C_REENABLE_SLAVE_RX = 0,
|
||||
MSS_I2C_PAUSE_SLAVE_RX = 1
|
||||
} mss_i2c_slave_handler_ret_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Slave write handler functions prototype.
|
||||
------------------------------------------------------------------------------
|
||||
This defines the function prototype that must be followed by MSS I2C slave
|
||||
write handler functions. These functions are registered with the MSS I2C driver
|
||||
through the MSS_I2C_register_write_handler() function.
|
||||
|
||||
Declaring and Implementing Slave Write Handler Functions:
|
||||
Slave write handler functions should follow the following prototype:
|
||||
mss_i2c_slave_handler_ret_t write_handler( uint8_t * data, uint16_t size );
|
||||
|
||||
The data parameter is a pointer to a buffer (received data buffer) holding
|
||||
the data written to the MSS I2C slave.
|
||||
The size parameter is the number of bytes held in the received data buffer.
|
||||
Handler functions must return one of the following values:
|
||||
• MSS_I2C_REENABLE_SLAVE_RX
|
||||
• MSS_I2C_PAUSE_SLAVE_RX.
|
||||
If the handler function returns MSS_I2C_REENABLE_SLAVE_RX, the driver will
|
||||
release the received data buffer and allow further I2C write transactions to
|
||||
the MSS I2C slave to take place.
|
||||
If the handler function returns MSS_I2C_PAUSE_SLAVE_RX, the MSS I2C slave
|
||||
will respond to subsequent write requests with a non-acknowledge bit (NACK),
|
||||
until the received data buffer content has been processed by some other part
|
||||
of the software application.
|
||||
A call to MSS_I2C_enable_slave_rx() is required at some point after
|
||||
returning MSS_I2C_PAUSE_SLAVE_RX in order to release the received data
|
||||
buffer so it can be used to store data received by subsequent I2C write
|
||||
transactions.
|
||||
*/
|
||||
typedef mss_i2c_slave_handler_ret_t (*mss_i2c_slave_wr_handler_t)( uint8_t *, uint16_t );
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
mss_i2c_instance_t
|
||||
------------------------------------------------------------------------------
|
||||
There is one instance of this structure for each of the microcontroller
|
||||
subsystem's I2Cs. Instances of this structure are used to identify a specific
|
||||
I2C. A pointer to an instance of the mss_i2c_instance_t structure is passed as
|
||||
the first parameter to MSS I2C driver functions to identify which I2C should
|
||||
perform the requested operation.
|
||||
*/
|
||||
typedef struct mss_i2c_instance
|
||||
{
|
||||
uint_fast8_t ser_address;
|
||||
/* Transmit related info:*/
|
||||
uint_fast8_t target_addr;
|
||||
|
||||
/* Current transaction type (WRITE, READ, RANDOM_READ)*/
|
||||
uint8_t transaction;
|
||||
|
||||
uint_fast16_t random_read_addr;
|
||||
|
||||
uint8_t options;
|
||||
|
||||
/* I2C hardware instance identification */
|
||||
IRQn_Type irqn;
|
||||
I2C_TypeDef * hw_reg;
|
||||
I2C_BitBand_TypeDef * hw_reg_bit;
|
||||
|
||||
/* TX INFO: */
|
||||
const uint8_t * tx_buffer;
|
||||
uint_fast16_t tx_size;
|
||||
uint_fast16_t tx_idx;
|
||||
uint_fast8_t dir;
|
||||
|
||||
/* RX INFO: */
|
||||
uint8_t * rx_buffer;
|
||||
uint_fast16_t rx_size;
|
||||
uint_fast16_t rx_idx;
|
||||
|
||||
/* status variable: */
|
||||
volatile mss_i2c_status_t status;
|
||||
|
||||
/* Slave data: */
|
||||
uint_fast8_t slave_mem_offset_length;
|
||||
mss_i2c_slave_wr_handler_t slave_write_handler;
|
||||
|
||||
} mss_i2c_instance_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
This instance of mss_i2c_instance_t holds all data related to the operations
|
||||
performed by MSS I2C 0. A pointer to g_mss_i2c0 is passed as the first
|
||||
parameter to MSS I2C driver functions to indicate that MSS I2C 0 should
|
||||
perform the requested operation.
|
||||
*/
|
||||
extern mss_i2c_instance_t g_mss_i2c0;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
This instance of mss_i2c_instance_t holds all data related to the operations
|
||||
performed by MSS I2C 1. A pointer to g_mss_i2c1 is passed as the first
|
||||
parameter to MSS I2C driver functions to indicate that MSS I2C 1 should
|
||||
perform the requested operation.
|
||||
*/
|
||||
extern mss_i2c_instance_t g_mss_i2c1;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
MSS I2C initialisation routine.
|
||||
------------------------------------------------------------------------------
|
||||
The MSS_I2C_init() function initializes and configures hardware and data
|
||||
structures of one of the SmartFusion MSS I2Cs.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block to be initialized. There are two such
|
||||
data structures, g_mss_i2c0 and g_mss_i2c1, associated with MSS I2C 0 and
|
||||
MSS I2C 1 respectively. This parameter must point to either the g_mss_i2c0
|
||||
or g_mss_i2c1 global data structure defined within the I2C driver.
|
||||
|
||||
@param ser_address:
|
||||
This parameter sets the I2C serial address being initialized. It is the I2C
|
||||
bus address to which the MSS I2C instance will respond. Any 8 bit address is
|
||||
allowed.
|
||||
|
||||
@param ser_clock_speed:
|
||||
This parameter sets the I2C serial clock frequency. It selects the divider
|
||||
that will be used to generate the serial clock from the APB clock. It can be
|
||||
one of the following:
|
||||
• MSS_I2C_PCLK_DIV_256
|
||||
• MSS_I2C_PCLK_DIV_224
|
||||
• MSS_I2C_PCLK_DIV_192
|
||||
• MSS_I2C_PCLK_DIV_160
|
||||
• MSS_I2C_PCLK_DIV_960
|
||||
• MSS_I2C_PCLK_DIV_120
|
||||
• MSS_I2C_PCLK_DIV_60
|
||||
• MSS_I2C_BCLK_DIV_8
|
||||
*/
|
||||
void MSS_I2C_init
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t ser_address,
|
||||
mss_i2c_clock_divider_t ser_clock_speed
|
||||
);
|
||||
|
||||
/*******************************************************************************
|
||||
*******************************************************************************
|
||||
*
|
||||
* Master specific functions
|
||||
*
|
||||
* The following functions are only used within an I2C master's implementation.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
I2C master write function.
|
||||
------------------------------------------------------------------------------
|
||||
This function initiates an I2C master write transaction. This function returns
|
||||
immediately after initiating the transaction. The content of the write buffer
|
||||
passed as parameter should not be modified until the write transaction
|
||||
completes. It also means that the memory allocated for the write buffer should
|
||||
not be freed or go out of scope before the write completes. You can check for
|
||||
the write transaction completion using the MSS_I2C_status() function.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
|
||||
@param serial_addr:
|
||||
This parameter specifies the serial address of the target I2C device.
|
||||
|
||||
@param write_buffer:
|
||||
This parameter is a pointer to a buffer holding the data to be written to
|
||||
the target I2C device.
|
||||
Care must be taken not to release the memory used by this buffer before the
|
||||
write transaction completes. For example, it is not appropriate to return
|
||||
from a function allocating this buffer as an array variable before the write
|
||||
transaction completes as this would result in the buffer's memory being
|
||||
de-allocated from the stack when the function returns. This memory could
|
||||
then be subsequently reused and modified causing unexpected data to be
|
||||
written to the target I2C device.
|
||||
|
||||
@param write_size:
|
||||
Number of bytes held in the write_buffer to be written to the target I2C
|
||||
device.
|
||||
|
||||
@param options:
|
||||
The options parameter is used to indicate if the I2C bus should be released
|
||||
on completion of the write transaction. Using the MSS_I2C_RELEASE_BUS
|
||||
constant for the options parameter causes a STOP bit to be generated at the
|
||||
end of the write transaction causing the bus to be released for other I2C
|
||||
devices to use. Using the MSS_I2C_HOLD_BUS constant as options parameter
|
||||
prevents a STOP bit from being generated at the end of the write
|
||||
transaction, preventing other I2C devices from initiating a bus transaction.
|
||||
*/
|
||||
void MSS_I2C_write
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t serial_addr,
|
||||
const uint8_t * write_buffer,
|
||||
uint16_t write_size,
|
||||
uint8_t options
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
I2C master read.
|
||||
------------------------------------------------------------------------------
|
||||
This function initiates an I2C master read transaction. This function returns
|
||||
immediately after initiating the transaction.
|
||||
The content of the read buffer passed as parameter should not be modified
|
||||
until the read transaction completes. It also means that the memory allocated
|
||||
for the read buffer should not be freed or go out of scope before the read
|
||||
completes. You can check for the read transaction completion using the
|
||||
MSS_I2C_status() function.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
|
||||
@param serial_addr:
|
||||
This parameter specifies the serial address of the target I2C device.
|
||||
|
||||
@param read_buffer
|
||||
Pointer to a buffer where the data received from the target device will be
|
||||
stored.
|
||||
Care must be taken not to release the memory used by this buffer before the
|
||||
read transaction completes. For example, it is not appropriate to return
|
||||
from a function allocating this buffer as an array variable before the read
|
||||
transaction completes as this would result in the buffer's memory being
|
||||
de-allocated from the stack when the function returns. This memory could
|
||||
then be subsequently reallocated resulting in the read transaction
|
||||
corrupting the newly allocated memory.
|
||||
|
||||
@param read_size:
|
||||
This parameter is the number of bytes to read from the target device. This
|
||||
size must not exceed the size of the read_buffer buffer.
|
||||
|
||||
@param options:
|
||||
The options parameter is used to indicate if the I2C bus should be released
|
||||
on completion of the read transaction. Using the MSS_I2C_RELEASE_BUS
|
||||
constant for the options parameter causes a STOP bit to be generated at the
|
||||
end of the read transaction causing the bus to be released for other I2C
|
||||
devices to use. Using the MSS_I2C_HOLD_BUS constant as options parameter
|
||||
prevents a STOP bit from being generated at the end of the read transaction,
|
||||
preventing other I2C devices from initiating a bus transaction.
|
||||
*/
|
||||
void MSS_I2C_read
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t serial_addr,
|
||||
uint8_t * read_buffer,
|
||||
uint16_t read_size,
|
||||
uint8_t options
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
I2C master write-read
|
||||
------------------------------------------------------------------------------
|
||||
This function initiates an I2C write-read transaction where data is first
|
||||
written to the target device before issuing a restart condition and changing
|
||||
the direction of the I2C transaction in order to read from the target device.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
|
||||
@param serial_addr:
|
||||
This parameter specifies the serial address of the target I2C device.
|
||||
|
||||
@param addr_offset:
|
||||
This parameter is a pointer to the buffer containing the data that will be
|
||||
sent to the slave during the write phase of the write-read transaction. This
|
||||
data is typically used to specify an address offset specifying to the I2C
|
||||
slave device what data it must return during the read phase of the
|
||||
write-read transaction.
|
||||
|
||||
@param offset_size:
|
||||
This parameter specifies the number of offset bytes to be written during the
|
||||
write phase of the write-read transaction. This is typically the size of the
|
||||
buffer pointed to by the addr_offset parameter.
|
||||
|
||||
@param read_buffer:
|
||||
This parameter is a pointer to the buffer where the data read from the I2C
|
||||
slave will be stored.
|
||||
|
||||
@param read_size:
|
||||
This parameter specifies the number of bytes to read from the target I2C
|
||||
slave device. This size must not exceed the size of the buffer pointed to by
|
||||
the read_buffer parameter.
|
||||
|
||||
@param options:
|
||||
The options parameter is used to indicate if the I2C bus should be released
|
||||
on completion of the write-read transaction. Using the MSS_I2C_RELEASE_BUS
|
||||
constant for the options parameter causes a STOP bit to be generated at the
|
||||
end of the write-read transaction causing the bus to be released for other
|
||||
I2C devices to use. Using the MSS_I2C_HOLD_BUS constant as options parameter
|
||||
prevents a STOP bit from being generated at the end of the write-read
|
||||
transaction, preventing other I2C devices from initiating a bus transaction.
|
||||
*/
|
||||
void MSS_I2C_write_read
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t serial_addr,
|
||||
const uint8_t * addr_offset,
|
||||
uint16_t offset_size,
|
||||
uint8_t * read_buffer,
|
||||
uint16_t read_size,
|
||||
uint8_t options
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
I2C status
|
||||
------------------------------------------------------------------------------
|
||||
This function indicates the current state of a MSS I2C instance.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
------------------------------------------------------------------------------
|
||||
@return
|
||||
The return value indicates the current state of a MSS I2C instance or the
|
||||
outcome of the previous transaction if no transaction is in progress.
|
||||
Possible return values are:
|
||||
SUCCESS
|
||||
The last I2C transaction has completed successfully.
|
||||
IN_PROGRESS
|
||||
There is an I2C transaction in progress.
|
||||
FAILED
|
||||
The last I2C transaction failed.
|
||||
|
||||
*/
|
||||
mss_i2c_status_t MSS_I2C_get_status
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Wait for I2C transaction completion.
|
||||
------------------------------------------------------------------------------
|
||||
This function waits for the current I2C transaction to complete. The return
|
||||
value indicates whether the last I2C transaction was successful, or is still
|
||||
in progress, or failed.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
------------------------------------------------------------------------------
|
||||
@return
|
||||
The return value indicates the outcome of the last I2C transaction. It can
|
||||
be one of the following:
|
||||
MSS_I2C_SUCCESS
|
||||
The last I2C transaction has completed successfully.
|
||||
MSS_I2C_IN_PROGRESS
|
||||
The current I2C transaction is still in progress.
|
||||
MSS_I2C_FAILED
|
||||
The last I2C transaction failed.
|
||||
*/
|
||||
mss_i2c_status_t MSS_I2C_wait_complete
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c
|
||||
);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*******************************************************************************
|
||||
*
|
||||
* Slave specific functions
|
||||
*
|
||||
* The following functions are only used within the implementation of an I2C
|
||||
* slave device.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
I2C slave transmit buffer configuration.
|
||||
------------------------------------------------------------------------------
|
||||
This function specifies the memory buffer holding the data that will be sent
|
||||
to the I2C master when this MSS I2C instance is the target of an I2C read or
|
||||
write-read transaction.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
|
||||
@param tx_buffer:
|
||||
This parameter is a pointer to the memory buffer holding the data to be
|
||||
returned to the I2C master when this MSS I2C instance is the target of an
|
||||
I2C read or write-read transaction.
|
||||
|
||||
@param tx_size:
|
||||
Size of the transmit buffer pointed to by the tx_buffer parameter.
|
||||
*/
|
||||
void MSS_I2C_set_slave_tx_buffer
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t * tx_buffer,
|
||||
uint16_t tx_size
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
I2C slave receive buffer configuration.
|
||||
------------------------------------------------------------------------------
|
||||
This function specifies the memory buffer that will be used by the MSS I2C
|
||||
instance to receive data when it is a slave. This buffer is the memory where
|
||||
data will be stored when the MSS I2C is the target of an I2C master write
|
||||
transaction (i.e. when it is the slave).
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
|
||||
@param rx_buffer:
|
||||
This parameter is a pointer to the memory buffer allocated by the caller
|
||||
software to be used as a slave receive buffer.
|
||||
|
||||
@param rx_size:
|
||||
Size of the slave receive buffer. This is the amount of memory that is
|
||||
allocated to the buffer pointed to by rx_buffer.
|
||||
Note: This buffer size will indirectly specify the maximum I2C write
|
||||
transaction length this MSS I2C instance can be the target of. This
|
||||
is because this MSS I2C instance will respond to further received
|
||||
bytes with a non-acknowledge bit (NACK) as soon as its receive
|
||||
buffer is full. This will cause the write transaction to fail.
|
||||
*/
|
||||
void MSS_I2C_set_slave_rx_buffer
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t * rx_buffer,
|
||||
uint16_t rx_size
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
I2C slave memory offset length configuration.
|
||||
------------------------------------------------------------------------------
|
||||
This function is used as part of the configuration of a MSS I2C instance for
|
||||
operation as a slave supporting write-read transactions. It specifies the
|
||||
number of bytes expected as part of the write phase of a write-read
|
||||
transaction. The bytes received during the write phase of a write-read
|
||||
transaction will be interpreted as an offset into the slave’s transmit buffer.
|
||||
This allows random access into the I2C slave transmit buffer from a remote
|
||||
I2C master.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
|
||||
@param offset_length:
|
||||
The offset_length parameter configures the number of bytes to be interpreted
|
||||
by the MSS I2C slave as a memory offset value during the write phase of
|
||||
write-read transactions.
|
||||
*/
|
||||
void MSS_I2C_set_slave_mem_offset_length
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
uint8_t offset_length
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
I2C write handler registration.
|
||||
------------------------------------------------------------------------------
|
||||
Register the function that will be called to process the data written to this
|
||||
MSS I2C instance when it is the slave in an I2C write transaction.
|
||||
Note: The write handler is not called as a result of a write-read transaction.
|
||||
The write data of a write read transaction is interpreted as an offset
|
||||
into the slave’s transmit buffer and handled by the driver.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
|
||||
@param handler:
|
||||
Pointer to the function that will process the I2C write request.
|
||||
*/
|
||||
void MSS_I2C_register_write_handler
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c,
|
||||
mss_i2c_slave_wr_handler_t handler
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
I2C slave receive enable.
|
||||
------------------------------------------------------------------------------
|
||||
Enables the MSS I2C instance identified through the this_i2c parameter to
|
||||
receive data when it is the target of an I2C write or write-read transaction.
|
||||
------------------------------------------------------------------------------
|
||||
@param this_i2c:
|
||||
The this_i2c parameter is a pointer to an mss_i2c_instance_t structure
|
||||
identifying the MSS I2C hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,
|
||||
associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must
|
||||
point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined
|
||||
within the I2C driver.
|
||||
*/
|
||||
void MSS_I2C_enable_slave_rx
|
||||
(
|
||||
mss_i2c_instance_t * this_i2c
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*MSS_I2C_H_*/
|
|
@ -0,0 +1,536 @@
|
|||
/*****************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* Author : Actel Application Team
|
||||
* Rev : 1.0.0.0
|
||||
* Description: Device driver for the on-board OLED for SmartFusion KITS
|
||||
* Implementation of sample basic driver for OLED display found on Actel
|
||||
* SmartFusion development boards.
|
||||
* This code is intended as an example of using the SmartFusion I2C driver.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "oled.h"
|
||||
#include "../bsp_config.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
Command definitions for the SSD300 controller inside the OLED display module.
|
||||
*/
|
||||
#define CMD_DISPLAY_OFF_SET 0xD3
|
||||
#define CMD_PANEL_ON 0xAF
|
||||
#define CMD_PANEL_OFF 0xAE
|
||||
#define CMD_DC_DC 0xAD
|
||||
#define CMD_DC_DC_DEFAULT_ON 0x8B
|
||||
#define CMD_DC_DC_OFF 0x8A
|
||||
#define CMD_DISPLAY_ALL_ON 0xA5
|
||||
#define CMD_DISPLAY_ALL_OFF 0xA4
|
||||
#define CMD_DISPLAY_NON_INV 0xA6
|
||||
#define CMD_DISPLAY_INV 0xA7
|
||||
#define CMD_ARECOL_LPM 0xD8
|
||||
#define CMD_ARECOL_MONO 0x00
|
||||
#define CMD_ARECOL_COLOR 0x30
|
||||
#define CMD_LPM_ON 0x05
|
||||
#define CMD_LPM_OFF 0x00
|
||||
#define CMD_CONTRAST 0x81
|
||||
#define CMD_MIRROR_HORI_ON 0xC8
|
||||
#define CMD_MIRROR_HORI_OFF 0xC0
|
||||
#define CMD_MIRROR_VERT_ON 0xA1
|
||||
#define CMD_MIRROR_VERT_OFF 0xA0
|
||||
#define CMD_HORI_SCRL 0x26
|
||||
#define CMD_HORI_SCRL_ON 0x2F
|
||||
#define CMD_HORI_SCRL_OFF 0x2E
|
||||
#define CMD_MUX_RATIO 0xA8
|
||||
#define CMD_MUX_RATIO_31 0x23
|
||||
|
||||
#define CMD_PAGE_0 0xB0
|
||||
#define CMD_PAGE_1 0xB1
|
||||
#define CMD_PAGE_2 0xB2
|
||||
#define CMD_PAGE_3 0xB3
|
||||
#define CMD_PAGE_4 0xB4
|
||||
#define CMD_PAGE_5 0xB5
|
||||
|
||||
#define CMD_LOW_NIB_COL 0x00
|
||||
#define CMD_HIGH_NIB_COL 0x10
|
||||
|
||||
#define CMD_START_LINE 0x50
|
||||
#define CONTRAST_DEFAULT 0xFF
|
||||
#define CONTRAST_25_PERC 0x40
|
||||
#define CONTRAST_100_PERC 0xFF
|
||||
#define CONTRAST_0_PERC 0x00
|
||||
#define SCROLL_1_COLUMN 0x01
|
||||
#define SCROLL_2_COLUMN 0x02
|
||||
#define SCROLL_3_COLUMN 0x03
|
||||
#define SCROLL_4_COLUMN 0x04
|
||||
#define SCROLL_PAGE_0 0x00
|
||||
#define SCROLL_PAGE_1 0x01
|
||||
#define SCROLL_PAGE_2 0x02
|
||||
#define SCROLL_PAGE_3 0x03
|
||||
#define SCROLL_PAGE_4 0x04
|
||||
#define SCROLL_PAGE_5 0x05
|
||||
#define SCROLL_12_FRAMES 0x00
|
||||
#define SCROLL_64_FRAMES 0x01
|
||||
#define SCROLL_128_FRAMES 0x02
|
||||
#define SCROLL_256_FRAMES 0x03
|
||||
#define SCROLL_PER_STEP 0x01
|
||||
#define PAGE0_COLOR_BAG 0x92
|
||||
#define PAGE1_COLOR_BAG 0x93
|
||||
|
||||
/***************************************************************************//**
|
||||
OLED display I2C communication protocol control byte values. Used to indicate
|
||||
whether the byte following the control byte is to be interpreted by the OLED
|
||||
display as a command or data byte.
|
||||
*/
|
||||
#define OLED_COMMAND_CODE 0x80
|
||||
#define OLED_DATA_CODE 0xC0
|
||||
|
||||
/***************************************************************************//**
|
||||
I2C serial address of OLED display.
|
||||
*/
|
||||
#define OLED_SLAVE_ADDRESS 0x78
|
||||
|
||||
/***************************************************************************//**
|
||||
Bitmaps of the character set.
|
||||
Each character is 5 pixels wide and 7 pixels high.
|
||||
The table is indexed on ASCII character codes.
|
||||
*/
|
||||
#define CHARACTER_WIDTH 5
|
||||
|
||||
const unsigned char oled_ascii_character_set[255][CHARACTER_WIDTH] =
|
||||
{
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
|
||||
{0x00, 0x00, 0x5F, 0x00, 0x00},
|
||||
{0x00, 0x07, 0x00, 0x07, 0x00},
|
||||
{0x14, 0x7F, 0x14, 0x7F, 0x14},
|
||||
{0x24, 0x2A, 0x7F, 0x2A, 0x12},
|
||||
{0x23, 0x13, 0x08, 0x64, 0x62},
|
||||
{0x36, 0x49, 0x55, 0x22, 0x50},
|
||||
{0x00, 0x05, 0x03, 0x00, 0x00},
|
||||
{0x00, 0x1C, 0x22, 0x41, 0x00},
|
||||
{0x00, 0x41, 0x22, 0x1C, 0x00},
|
||||
{0x14, 0x08, 0x3E, 0x08, 0x14},
|
||||
{0x08, 0x08, 0x3E, 0x08, 0x08},
|
||||
{0x00, 0x50, 0x30, 0x00, 0x00},
|
||||
{0x08, 0x08, 0x08, 0x08, 0x08},
|
||||
{0x00, 0x60, 0x60, 0x00, 0x00},
|
||||
{0x20, 0x10, 0x08, 0x04, 0x02},
|
||||
{0x3E, 0x51, 0x49, 0x45, 0x3E},
|
||||
{0x00, 0x42, 0x7F, 0x40, 0x00},
|
||||
{0x42, 0x61, 0x51, 0x49, 0x46},
|
||||
{0x21, 0x41, 0x45, 0x4B, 0x31},
|
||||
{0x18, 0x14, 0x12, 0x7F, 0x10},
|
||||
{0x27, 0x45, 0x45, 0x45, 0x39},
|
||||
{0x3C, 0x4A, 0x49, 0x49, 0x30},
|
||||
{0x01, 0x71, 0x09, 0x05, 0x03},
|
||||
{0x36, 0x49, 0x49, 0x49, 0x36},
|
||||
{0x06, 0x49, 0x49, 0x29, 0x1E},
|
||||
{0x00, 0x36, 0x36, 0x00, 0x00},
|
||||
{0x00, 0x56, 0x36, 0x00, 0x00},
|
||||
{0x08, 0x14, 0x22, 0x41, 0x00},
|
||||
{0x14, 0x14, 0x14, 0x14, 0x14},
|
||||
{0x00, 0x41, 0x22, 0x14, 0x08},
|
||||
{0x02, 0x01, 0x51, 0x09, 0x06},
|
||||
{0x32, 0x49, 0x79, 0x41, 0x3E},
|
||||
{0x7E, 0x11, 0x11, 0x11, 0x7E},
|
||||
{0x7F, 0x49, 0x49, 0x49, 0x36},
|
||||
{0x3E, 0x41, 0x41, 0x41, 0x22},
|
||||
{0x7F, 0x41, 0x41, 0x22, 0x1C},
|
||||
{0x7F, 0x49, 0x49, 0x49, 0x41},
|
||||
{0x7F, 0x09, 0x09, 0x09, 0x01},
|
||||
{0x3E, 0x41, 0x49, 0x49, 0x7A},
|
||||
{0x7F, 0x08, 0x08, 0x08, 0x7F},
|
||||
{0x00, 0x41, 0x7F, 0x41, 0x00},
|
||||
{0x20, 0x40, 0x41, 0x3F, 0x01},
|
||||
{0x7F, 0x08, 0x14, 0x22, 0x41},
|
||||
{0x3F, 0x40, 0x40, 0x40, 0x40},
|
||||
{0x7F, 0x02, 0x0C, 0x02, 0x7F},
|
||||
{0x7F, 0x04, 0x08, 0x10, 0x7F},
|
||||
{0x3E, 0x41, 0x41, 0x41, 0x3E},
|
||||
{0x7F, 0x09, 0x09, 0x09, 0x06},
|
||||
{0x3E, 0x41, 0x51, 0x21, 0x5E},
|
||||
{0x7F, 0x09, 0x19, 0x29, 0x46},
|
||||
{0x46, 0x49, 0x49, 0x49, 0x31},
|
||||
{0x01, 0x01, 0x7F, 0x01, 0x01},
|
||||
{0x3F, 0x40, 0x40, 0x40, 0x3F},
|
||||
{0x1F, 0x20, 0x40, 0x20, 0x1F},
|
||||
{0x3F, 0x40, 0x38, 0x40, 0x3F},
|
||||
{0x63, 0x14, 0x08, 0x14, 0x63},
|
||||
{0x07, 0x08, 0x70, 0x08, 0x07},
|
||||
{0x61, 0x51, 0x49, 0x45, 0x43},
|
||||
{0x00, 0x7F, 0x41, 0x41, 0x00},
|
||||
{0x02, 0x04, 0x08, 0x10, 0x20},
|
||||
{0x00, 0x41, 0x41, 0x7F, 0x00},
|
||||
{0x04, 0x02, 0x01, 0x02, 0x04},
|
||||
{0x40, 0x40, 0x40, 0x40, 0x40},
|
||||
{0x00, 0x01, 0x02, 0x04, 0x00},
|
||||
{0x20, 0x54, 0x54, 0x54, 0x78},
|
||||
{0x7F, 0x48, 0x44, 0x44, 0x38},
|
||||
{0x38, 0x44, 0x44, 0x44, 0x20},
|
||||
{0x30, 0x48, 0x48, 0x50, 0x7F},
|
||||
{0x38, 0x54, 0x54, 0x54, 0x18},
|
||||
{0x10, 0x7E, 0x11, 0x01, 0x02},
|
||||
{0x0C, 0x52, 0x52, 0x52, 0x3E},
|
||||
{0x7F, 0x08, 0x04, 0x04, 0x78},
|
||||
{0x00, 0x44, 0x7D, 0x40, 0x00},
|
||||
{0x20, 0x40, 0x44, 0x3D, 0x00},
|
||||
{0x7F, 0x10, 0x28, 0x44, 0x00},
|
||||
{0x00, 0x41, 0x7F, 0x40, 0x00},
|
||||
{0x7C, 0x04, 0x18, 0x04, 0x78},
|
||||
{0x7C, 0x08, 0x04, 0x04, 0x78},
|
||||
{0x38, 0x44, 0x44, 0x44, 0x38},
|
||||
{0x7C, 0x14, 0x14, 0x14, 0x08},
|
||||
{0x08, 0x14, 0x14, 0x18, 0x7C},
|
||||
{0x7C, 0x08, 0x04, 0x04, 0x08},
|
||||
{0x48, 0x54, 0x54, 0x54, 0x20},
|
||||
{0x04, 0x3F, 0x44, 0x40, 0x20},
|
||||
{0x3C, 0x40, 0x40, 0x20, 0x7C},
|
||||
{0x1C, 0x20, 0x40, 0x20, 0x1C},
|
||||
{0x3C, 0x40, 0x30, 0x40, 0x3C},
|
||||
{0x44, 0x28, 0x10, 0x28, 0x44},
|
||||
{0x0C, 0x50, 0x50, 0x50, 0x3C},
|
||||
{0x44, 0x64, 0x54, 0x4C, 0x44},
|
||||
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
|
||||
{0x07, 0x05, 0x07, 0x00, 0x00},
|
||||
{0x12, 0x19, 0x16, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
|
||||
};
|
||||
|
||||
#define FIRST_CHARACTER 0
|
||||
|
||||
/***************************************************************************//**
|
||||
The g_p_oled_i2c global variable is only used inside the OLED driver. It
|
||||
identifies the MSS I2C block used to communicate with the OLED display.
|
||||
*/
|
||||
static mss_i2c_instance_t * g_p_oled_i2c = OLED_I2C_INSTANCE;
|
||||
|
||||
/***************************************************************************//**
|
||||
The OLED_set_cursor function sets the cursor position.
|
||||
|
||||
@param line
|
||||
The line parameter specifies the line at which to set the cursor. It can
|
||||
take the values:
|
||||
- FIRST_LINE
|
||||
- SECOND_LINE
|
||||
|
||||
@param char_offset
|
||||
The char_offset paraemter specifies the character offset on a line where to
|
||||
set the cursor location. It can be set to FIRST_CHARACTER to set the cursor
|
||||
at the start of a line.
|
||||
*/
|
||||
void OLED_set_cursor
|
||||
(
|
||||
uint8_t line,
|
||||
uint8_t char_offset
|
||||
);
|
||||
/***************************************************************************//**
|
||||
The OLED_write_string function displays the input string to the OLED panel.
|
||||
|
||||
@param string
|
||||
The string parameter is a pointer to the zero-terminated to display on the
|
||||
OLED.
|
||||
*/
|
||||
void OLED_write_string( const char *string);
|
||||
|
||||
/***************************************************************************//**
|
||||
The OLED_write_char function displays a single character to the display.
|
||||
|
||||
@param data_char
|
||||
The data_char parameter is the ASCII code of the character to display.
|
||||
*/
|
||||
void OLED_write_char( const uint8_t data_char );
|
||||
/***************************************************************************//**
|
||||
OLED_init()
|
||||
See "oled.h" for details of how to use this function.
|
||||
*/
|
||||
void OLED_init(void )
|
||||
{
|
||||
uint8_t oled_init_sequence1[] =
|
||||
{
|
||||
OLED_COMMAND_CODE, CMD_DISPLAY_NON_INV,
|
||||
OLED_COMMAND_CODE, CMD_DISPLAY_ALL_OFF,
|
||||
OLED_COMMAND_CODE, CMD_MIRROR_HORI_ON,
|
||||
OLED_COMMAND_CODE, CMD_MIRROR_VERT_OFF,
|
||||
OLED_COMMAND_CODE, CMD_HORI_SCRL_OFF,
|
||||
OLED_COMMAND_CODE, CMD_CONTRAST,
|
||||
OLED_COMMAND_CODE, CONTRAST_DEFAULT,
|
||||
OLED_COMMAND_CODE, CMD_ARECOL_LPM,
|
||||
OLED_COMMAND_CODE, CMD_ARECOL_MONO^CMD_LPM_OFF
|
||||
};
|
||||
|
||||
uint8_t oled_init_sequence2[] =
|
||||
{
|
||||
OLED_COMMAND_CODE, CMD_START_LINE,
|
||||
OLED_COMMAND_CODE, CMD_PANEL_ON
|
||||
};
|
||||
|
||||
MSS_I2C_init( g_p_oled_i2c, OLED_SLAVE_ADDRESS, MSS_I2C_PCLK_DIV_60 );
|
||||
|
||||
MSS_I2C_write( g_p_oled_i2c, OLED_SLAVE_ADDRESS, oled_init_sequence1, sizeof(oled_init_sequence1), MSS_I2C_RELEASE_BUS );
|
||||
MSS_I2C_wait_complete( g_p_oled_i2c );
|
||||
|
||||
OLED_clear_display(BOTH_LINES);
|
||||
|
||||
MSS_I2C_write( g_p_oled_i2c, OLED_SLAVE_ADDRESS, oled_init_sequence2, sizeof(oled_init_sequence2), MSS_I2C_RELEASE_BUS );
|
||||
MSS_I2C_wait_complete( g_p_oled_i2c );
|
||||
|
||||
OLED_set_cursor( FIRST_LINE, FIRST_CHARACTER );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
OLED_clear_display()
|
||||
See "oled.h" for details of how to use this function.
|
||||
*/
|
||||
void OLED_clear_display( oled_no_of_line LINES )
|
||||
{
|
||||
uint8_t i, j,start_line,end_line;
|
||||
uint8_t clear_8_columns[] =
|
||||
{
|
||||
OLED_DATA_CODE, 0x00,
|
||||
OLED_DATA_CODE, 0x00,
|
||||
OLED_DATA_CODE, 0x00,
|
||||
OLED_DATA_CODE, 0x00,
|
||||
OLED_DATA_CODE, 0x00,
|
||||
OLED_DATA_CODE, 0x00,
|
||||
OLED_DATA_CODE, 0x00,
|
||||
OLED_DATA_CODE, 0x00
|
||||
};
|
||||
|
||||
switch(LINES)
|
||||
{
|
||||
case FIRST_LINE:
|
||||
{
|
||||
start_line = FIRST_LINE;
|
||||
end_line = FIRST_LINE;
|
||||
}
|
||||
|
||||
case SECOND_LINE:
|
||||
{
|
||||
start_line = SECOND_LINE;
|
||||
end_line = SECOND_LINE;
|
||||
}
|
||||
|
||||
case BOTH_LINES:
|
||||
{
|
||||
start_line = FIRST_LINE;
|
||||
end_line = SECOND_LINE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for( j = start_line; j <= end_line; ++j )
|
||||
{
|
||||
OLED_set_cursor( j, FIRST_CHARACTER );
|
||||
for( i = 0; i < 13; ++i )
|
||||
{
|
||||
MSS_I2C_write( g_p_oled_i2c, OLED_SLAVE_ADDRESS, clear_8_columns, sizeof(clear_8_columns), MSS_I2C_RELEASE_BUS );
|
||||
MSS_I2C_wait_complete( g_p_oled_i2c );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
OLED_set_cursor()
|
||||
See definition of OLED_set_cursor() for details of how to use this function.
|
||||
*/
|
||||
void OLED_set_cursor
|
||||
(
|
||||
uint8_t line,
|
||||
uint8_t char_offset
|
||||
)
|
||||
{
|
||||
uint8_t command_sequence[] =
|
||||
{
|
||||
OLED_COMMAND_CODE, CMD_LOW_NIB_COL,
|
||||
OLED_COMMAND_CODE, CMD_HIGH_NIB_COL,
|
||||
OLED_COMMAND_CODE, CMD_PAGE_0
|
||||
};
|
||||
uint8_t low_nib, high_nib;
|
||||
|
||||
++char_offset;
|
||||
char_offset *= CHARACTER_WIDTH;
|
||||
low_nib = 0x0F & char_offset;
|
||||
high_nib = (0xF0 & char_offset) >> 4;
|
||||
line += 2;
|
||||
|
||||
command_sequence[1] |= low_nib;
|
||||
command_sequence[3] |= high_nib;
|
||||
command_sequence[5] |= line;
|
||||
MSS_I2C_write( g_p_oled_i2c, OLED_SLAVE_ADDRESS, command_sequence, sizeof(command_sequence), MSS_I2C_RELEASE_BUS );
|
||||
MSS_I2C_wait_complete( g_p_oled_i2c );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
OLED_write_string()
|
||||
See definition of OLED_write_string for details of how to use this function.
|
||||
*/
|
||||
void OLED_write_string
|
||||
(
|
||||
const char *string
|
||||
)
|
||||
{
|
||||
while (*string != 0)
|
||||
{
|
||||
OLED_write_char( *string );
|
||||
++string;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
OLED_write_char()
|
||||
See definition of OLED_write_char() for details of how to use this function.
|
||||
*/
|
||||
void OLED_write_char
|
||||
(
|
||||
const uint8_t data_char
|
||||
)
|
||||
{
|
||||
uint8_t txbuff[10];
|
||||
uint8_t i;
|
||||
|
||||
for ( i = 0; i < CHARACTER_WIDTH; ++i )
|
||||
{
|
||||
txbuff[i * 2] = OLED_DATA_CODE;
|
||||
txbuff[(i * 2) + 1] = oled_ascii_character_set[data_char][i];
|
||||
}
|
||||
MSS_I2C_write( g_p_oled_i2c, OLED_SLAVE_ADDRESS, txbuff, sizeof(txbuff), MSS_I2C_RELEASE_BUS );
|
||||
MSS_I2C_wait_complete( g_p_oled_i2c );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
OLED_horizontal_scroll()
|
||||
See "oled.h" for details of how to use this function.
|
||||
*/
|
||||
void OLED_horizontal_scroll(struct oled_data * horiz_scroll)
|
||||
{
|
||||
uint8_t horiz_scroll_on_off[] =
|
||||
{
|
||||
OLED_COMMAND_CODE, CMD_HORI_SCRL_OFF,
|
||||
};
|
||||
|
||||
uint8_t horiz_scroll_setup_data[] =
|
||||
{
|
||||
OLED_COMMAND_CODE, CMD_HORI_SCRL,
|
||||
OLED_COMMAND_CODE, SCROLL_PER_STEP,
|
||||
OLED_COMMAND_CODE, SCROLL_PAGE_0,
|
||||
OLED_COMMAND_CODE, SCROLL_12_FRAMES,
|
||||
OLED_COMMAND_CODE, SCROLL_PAGE_1,
|
||||
};
|
||||
MSS_I2C_write( g_p_oled_i2c, OLED_SLAVE_ADDRESS, horiz_scroll_on_off, sizeof(horiz_scroll_on_off), MSS_I2C_RELEASE_BUS );
|
||||
MSS_I2C_wait_complete( g_p_oled_i2c );
|
||||
|
||||
if(horiz_scroll->on_off == 1)
|
||||
{
|
||||
horiz_scroll_setup_data[3] = horiz_scroll->column_scrool_per_step;
|
||||
horiz_scroll_setup_data[5] = horiz_scroll->start_page;
|
||||
horiz_scroll_setup_data[7] = horiz_scroll->time_intrval_btw_scroll_step;
|
||||
horiz_scroll_setup_data[9] = horiz_scroll->end_page;
|
||||
MSS_I2C_write( g_p_oled_i2c, OLED_SLAVE_ADDRESS, horiz_scroll_setup_data, sizeof(horiz_scroll_setup_data), MSS_I2C_RELEASE_BUS );
|
||||
MSS_I2C_wait_complete( g_p_oled_i2c );
|
||||
|
||||
horiz_scroll_on_off[1] = CMD_HORI_SCRL_ON;
|
||||
MSS_I2C_write( g_p_oled_i2c, OLED_SLAVE_ADDRESS, horiz_scroll_on_off, sizeof(horiz_scroll_on_off), MSS_I2C_RELEASE_BUS );
|
||||
MSS_I2C_wait_complete( g_p_oled_i2c );
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
OLED_contrast()
|
||||
See "oled.h" for details of how to use this function.
|
||||
*/
|
||||
void OLED_contrast(uint8_t color_contrast)
|
||||
{
|
||||
uint8_t oled_contrast[] =
|
||||
{
|
||||
OLED_COMMAND_CODE, CMD_CONTRAST,
|
||||
OLED_COMMAND_CODE, CONTRAST_DEFAULT,
|
||||
};
|
||||
|
||||
oled_contrast[3] = color_contrast;
|
||||
MSS_I2C_write( g_p_oled_i2c, OLED_SLAVE_ADDRESS, oled_contrast, sizeof(oled_contrast), MSS_I2C_RELEASE_BUS );
|
||||
MSS_I2C_wait_complete( g_p_oled_i2c );
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
OLED_write_data()
|
||||
See "oled.h" for details of how to use this function.
|
||||
*/
|
||||
void OLED_write_data(struct oled_data* data, oled_no_of_line LINES)
|
||||
{
|
||||
uint8_t line;
|
||||
uint8_t char_offset;
|
||||
char *string;
|
||||
|
||||
switch(LINES)
|
||||
{
|
||||
|
||||
case FIRST_LINE:
|
||||
{
|
||||
OLED_clear_display(FIRST_LINE);
|
||||
line = data->line1;
|
||||
char_offset = data->char_offset1;
|
||||
string = data->string1;
|
||||
}
|
||||
|
||||
case SECOND_LINE:
|
||||
{
|
||||
OLED_clear_display(SECOND_LINE);
|
||||
line = data->line2;
|
||||
char_offset = data->char_offset2;
|
||||
string = data->string2;
|
||||
}
|
||||
|
||||
case BOTH_LINES:
|
||||
{
|
||||
OLED_clear_display(BOTH_LINES);
|
||||
line = data->line1;
|
||||
char_offset = data->char_offset1;
|
||||
string = data->string1;
|
||||
OLED_set_cursor(line,char_offset);
|
||||
OLED_write_string(string);
|
||||
line = data->line2;
|
||||
char_offset = data->char_offset2;
|
||||
string = data->string2;
|
||||
}
|
||||
|
||||
OLED_set_cursor(line,char_offset);
|
||||
OLED_write_string(string);
|
||||
OLED_contrast(data->contrast_val);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/*****************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* Author : Actel Application Team
|
||||
* Rev : 1.0.0.0
|
||||
* Description: Device driver for the on-board OLED for SmartFusion KITS
|
||||
* API of sample basic driver for OLED display found on Actel SmartFusion
|
||||
* development boards.
|
||||
* This code is intended as an example of using the SmartFusion I2C driver.
|
||||
*
|
||||
*/
|
||||
#ifndef OLED_H_
|
||||
#define OLED_H_
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#define OLED_HORIZ_SCROLL_ON 0x01
|
||||
#define OLED_HORIZ_SCROLL_OFF 0x00
|
||||
#define OLED_HORIZ_SCROLL_STEP 0x08
|
||||
#define OLED_CONTRAST_VAL 0xFF
|
||||
#define OLED_START_PAGE 0x01
|
||||
#define OLED_HORIZ_SCROLL_TINVL 0x00
|
||||
#define OLED_END_PAGE 0x05
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* The oled_no_of_line type represents number of lines to be written on OLED.
|
||||
FIRST LINE : The OLED cursor is set to line number 1 and only 1 line is
|
||||
printed on OLED
|
||||
SECOND_LINE : The OLED cursor is set to line number 2 and only 1 line is
|
||||
printed on OLED
|
||||
BOTH_LINES : The OLED cursor is set to line number 1 and line 1 and line 2
|
||||
are printed on OLED
|
||||
*/
|
||||
typedef enum {
|
||||
FIRST_LINE = 0,
|
||||
SECOND_LINE,
|
||||
BOTH_LINES
|
||||
} oled_no_of_line;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
oled_data
|
||||
------------------------------------------------------------------------------
|
||||
There is one instance of this structure for OLED data. Instances of this
|
||||
structure is used to provide the data to OLED. A pointer to an instance of
|
||||
the oled_data structure is passed as the parameter OLED driver functions.
|
||||
*/
|
||||
struct oled_data
|
||||
{
|
||||
/* Represents line number, where String 1 has to be printed */
|
||||
uint8_t line1;
|
||||
/* Represents character offset within the line1, from where String 1 has to be
|
||||
* printed */
|
||||
uint8_t char_offset1;
|
||||
/* Represents line number, where String 2 has to be printed */
|
||||
uint8_t line2;
|
||||
/* Represents character offset within the line2, from where String 2 has to be
|
||||
* printed */
|
||||
uint8_t char_offset2;
|
||||
/* String 1 holds the data to be displayed on line 1 of OLED, It has to be
|
||||
* less that 49 characters*/
|
||||
char *string1;
|
||||
/* String 1 holds the data to be displayed on line 2 of OLED, It has to be
|
||||
* less that 49 characters*/
|
||||
char *string2;
|
||||
/* Holds the contrast value to be set for String 1 and String 2 */
|
||||
uint8_t contrast_val;
|
||||
/* Represents ON or OFF for horizontal scrolling */
|
||||
uint8_t on_off;
|
||||
/* Represents number of coumns scrolls per step for horizontal scroll*/
|
||||
unsigned char column_scrool_per_step;
|
||||
/* Represents start page for horizontal scroll*/
|
||||
unsigned char start_page;
|
||||
/* Represents time interval for horizontal scroll*/
|
||||
unsigned char time_intrval_btw_scroll_step;
|
||||
/* Represents end page for horizontal scroll*/
|
||||
unsigned char end_page;
|
||||
|
||||
};
|
||||
/***************************************************************************//**
|
||||
The following defines can be used as parameter to the OLED_set_cursor()
|
||||
function.
|
||||
*/
|
||||
|
||||
/***************************************************************************//**
|
||||
The OLED_init function initializes the OLED display.
|
||||
*/
|
||||
void vOLEDInit( void );
|
||||
void OLED_init( void );
|
||||
|
||||
/***************************************************************************//**
|
||||
This function(OLED_clear_display) clears the content of the display RAM
|
||||
based on the LINES input.
|
||||
------------------------------------------------------------------------------
|
||||
@param oled_no_of_line:
|
||||
The oled_no_of_line parameter enum that holds Number of lines.
|
||||
If FIRST_LINE is passed as parameter to this function thnen, this functions
|
||||
clears only First line that is 0
|
||||
If SECOND_LINE is passed as parameter to this function thnen, this functions
|
||||
clears only Second line that is 1
|
||||
If BOTH_LINE is passed as parameter to this function thnen, this functions
|
||||
clears entire OLED display.
|
||||
*/
|
||||
void OLED_clear_display( oled_no_of_line LINES );
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
OLED Write data.
|
||||
------------------------------------------------------------------------------
|
||||
This function (OLED_write_data ) writes the data to OLED basedon the
|
||||
parameters passed to this function.
|
||||
------------------------------------------------------------------------------
|
||||
@param data:
|
||||
The data parameter is a pointer to an oled_data structure, that holds
|
||||
different fields of data to be required for OLED (see the oled_data structure
|
||||
definition).
|
||||
|
||||
@param oled_no_of_line:
|
||||
The oled_no_of_line parameter enum that holds Number of lines.
|
||||
If FIRST_LINE is passed as parameter to this function thnen, this functions
|
||||
wtites string 1 at FIRST LINE
|
||||
If SECOND_LINE is passed as parameter to this function thnen, this functions
|
||||
wtites string 1 at SECOND LINE
|
||||
If BOTH_LINE is passed as parameter to this function thnen, this functions
|
||||
wtites string 1 and string 2 at FIRST LINE and SECOND LINE respectively.
|
||||
Example:
|
||||
@code
|
||||
#include "drivers/mss_watchdog/mss_watchdog.h"
|
||||
#include "oled.h"
|
||||
#define FIRST_CHARACTER 0
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
char *string1="SmartFusion";
|
||||
char *string2="INNOVATIVE ";
|
||||
struct oled_data write_data;
|
||||
|
||||
write_data.line1 = FIRST_LINE;
|
||||
write_data.char_offset1 = FIRST_CHARACTER;
|
||||
write_data.string1 = string1;
|
||||
write_data.line2 = SECOND_LINE;
|
||||
write_data.char_offset2 = FIRST_CHARACTER;
|
||||
write_data.string2 = string2;
|
||||
write_data.contrast_val = 0x01;
|
||||
|
||||
MSS_WD_disable();
|
||||
OLED_init();
|
||||
OLED_write_data(&write_data,BOTH_LINES);
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
|
||||
void OLED_write_data(struct oled_data * data, oled_no_of_line flag);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
OLED Horizontal scrolling.
|
||||
------------------------------------------------------------------------------
|
||||
This function (OLED_horizontal_scroll ) enbles the Horizontal scrolling.
|
||||
------------------------------------------------------------------------------
|
||||
@param data:
|
||||
The horiz_scroll parameter is a pointer to an oled_data structure, that holds
|
||||
different fields of data to be required for OLED (see the oled_data structure
|
||||
definition).
|
||||
Example:
|
||||
@code
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
char *string1="SmartFusion";
|
||||
char *string2="INNOVATIVE ";
|
||||
struct oled_data write_data;
|
||||
|
||||
write_data.line1 = FIRST_LINE;
|
||||
write_data.char_offset1 = FIRST_CHARACTER;
|
||||
write_data.string1 = string1;
|
||||
write_data.line2 = SECOND_LINE;
|
||||
write_data.char_offset2 = FIRST_CHARACTER;
|
||||
write_data.string2 = string2;
|
||||
write_data.contrast_val = 0x01;
|
||||
write_data.on_off = 0x01;
|
||||
write_data.column_scrool_per_step = 0x08;
|
||||
write_data.start_page = 0x01;
|
||||
write_data.time_intrval_btw_scroll_step = 0x00;
|
||||
write_data.end_page = 0x05;
|
||||
|
||||
MSS_WD_disable();
|
||||
OLED_init();
|
||||
OLED_write_data(&write_data,BOTH_LINES);
|
||||
OLED_horizontal_scroll(&write_data);
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
|
||||
void OLED_horizontal_scroll(struct oled_data * horiz_scroll);
|
||||
|
||||
/***************************************************************************//**
|
||||
This function(OLED_contrast) sets ths conrtast to the data displayed on the
|
||||
OLED.
|
||||
------------------------------------------------------------------------------
|
||||
@param color_contrast:
|
||||
The color_contrast parameter that holds contrast value.
|
||||
The color_contrast values should be in the range of 1 to 256.
|
||||
*/
|
||||
void OLED_contrast(uint8_t color_contrast);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*****************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Author : Actel Application Team
|
||||
* Rev : 1.0.0.0
|
||||
* Description: Configuration for the ON-BOARD peripherals for SmartFusion KITS.
|
||||
*
|
||||
*******************************************************************************/
|
||||
#ifndef BSP_CONFIG_H_
|
||||
#define BSP_CONFIG_H_
|
||||
|
||||
#include "i2c.h"
|
||||
/* Configuration for OLED */
|
||||
#define OLED_I2C_INSTANCE &g_mss_i2c0
|
||||
|
||||
/* Configuration for the SPI Flash */
|
||||
#define SPI_FLASH_ON_SF_DEV_KIT 0
|
||||
#define SPI_FLASH_ON_SF_EVAL_KIT 1
|
||||
|
||||
#define USE_DMA_FOR_SPI_FLASH 1
|
||||
#define SPI_FLASH_DMA_CHANNEL 0
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,831 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SVN $Revision: 2905 $
|
||||
* SVN $Date: 2010-08-20 14:03:28 +0100 (Fri, 20 Aug 2010) $
|
||||
*/
|
||||
#include "mss_ace.h"
|
||||
#include "mss_ace_configurator.h"
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
#include "../../drivers_config/mss_ace/ace_handles.h"
|
||||
#include "../../drivers_config/mss_ace/ace_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
extern ace_channel_desc_t g_ace_channel_desc_table[ACE_NB_OF_INPUT_CHANNELS];
|
||||
extern ace_adc_config_t g_ace_adc_config[ACE_NB_OF_ADC];
|
||||
extern const uint32_t g_ace_current_resistors[ACE_NB_OF_CURRENT_MONITORS];
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
static uint16_t convert_mV_to_ppe_value
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint32_t voltage
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ace_init_convert(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
#define VOLTAGE_CHANNEL 0u
|
||||
#define CURRENT_CHANNEL 1u
|
||||
#define TEMPERATURE_CHANNEL 2u
|
||||
#define INVALID_CHANNEL 0xFFu
|
||||
|
||||
static const uint8_t channel_type_lut[] =
|
||||
{
|
||||
VOLTAGE_CHANNEL, /* ADC0_1P5V = 0 */
|
||||
VOLTAGE_CHANNEL, /* ABPS0 = 1 */
|
||||
VOLTAGE_CHANNEL, /* ABPS1 = 2 */
|
||||
CURRENT_CHANNEL, /* CM0 = 3 */
|
||||
TEMPERATURE_CHANNEL, /* TM0 = 4 */
|
||||
VOLTAGE_CHANNEL, /* ABPS2 = 5 */
|
||||
VOLTAGE_CHANNEL, /* ABPS3 = 6 */
|
||||
CURRENT_CHANNEL, /* CM1 = 7 */
|
||||
TEMPERATURE_CHANNEL, /* TM1 = 8 */
|
||||
VOLTAGE_CHANNEL, /* ADC0 = 9 */
|
||||
VOLTAGE_CHANNEL, /* ADC1 = 10 */
|
||||
VOLTAGE_CHANNEL, /* ADC2 = 11 */
|
||||
VOLTAGE_CHANNEL, /* ADC3 = 12 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
VOLTAGE_CHANNEL, /* SDD0_IN = 15 */
|
||||
|
||||
VOLTAGE_CHANNEL, /* ADC1_1P5V = 16 */
|
||||
VOLTAGE_CHANNEL, /* ABPS4 = 17 */
|
||||
VOLTAGE_CHANNEL, /* ABPS5 = 18 */
|
||||
CURRENT_CHANNEL, /* CM2 = 19 */
|
||||
TEMPERATURE_CHANNEL, /* TM2 = 20 */
|
||||
VOLTAGE_CHANNEL, /* ABPS6 = 21 */
|
||||
VOLTAGE_CHANNEL, /* ABPS7 = 22 */
|
||||
CURRENT_CHANNEL, /* CM3 = 23 */
|
||||
TEMPERATURE_CHANNEL, /* TM3 = 24 */
|
||||
VOLTAGE_CHANNEL, /* ADC4 = 25 */
|
||||
VOLTAGE_CHANNEL, /* ADC5 = 26 */
|
||||
VOLTAGE_CHANNEL, /* ADC6 = 27 */
|
||||
VOLTAGE_CHANNEL, /* ADC7 = 28 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
VOLTAGE_CHANNEL, /* SDD1_IN = 31 */
|
||||
|
||||
VOLTAGE_CHANNEL, /* ADC2_1P5V = 32 */
|
||||
VOLTAGE_CHANNEL, /* ABPS8 = 33 */
|
||||
VOLTAGE_CHANNEL, /* ABPS9 = 34 */
|
||||
CURRENT_CHANNEL, /* CM4 = 35 */
|
||||
TEMPERATURE_CHANNEL, /* TM4 = 36 */
|
||||
VOLTAGE_CHANNEL, /* ABPS10 = 37 */
|
||||
VOLTAGE_CHANNEL, /* ABPS11 = 38 */
|
||||
CURRENT_CHANNEL, /* CM5 = 39 */
|
||||
TEMPERATURE_CHANNEL, /* TM5 = 40 */
|
||||
VOLTAGE_CHANNEL, /* ADC8 = 41 */
|
||||
VOLTAGE_CHANNEL, /* ADC9 = 42 */
|
||||
VOLTAGE_CHANNEL, /* ADC10 = 43 */
|
||||
VOLTAGE_CHANNEL, /* ADC11 = 44 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
VOLTAGE_CHANNEL /* SDD2_IN = 47 */
|
||||
};
|
||||
|
||||
static const uint8_t channel_quad_lut[] =
|
||||
{
|
||||
0xFFu, /* ADC0_1P5V = 0 */
|
||||
0u, /* ABPS0 = 1 */
|
||||
0u, /* ABPS1 = 2 */
|
||||
0u, /* CM0 = 3 */
|
||||
0u, /* TM0 = 4 */
|
||||
1u, /* ABPS2 = 5 */
|
||||
1u, /* ABPS3 = 6 */
|
||||
1u, /* CM1 = 7 */
|
||||
1u, /* TM1 = 8 */
|
||||
0xFFu, /* ADC0 = 9 */
|
||||
0xFFu, /* ADC1 = 10 */
|
||||
0xFFu, /* ADC2 = 11 */
|
||||
0xFFu, /* ADC3 = 12 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
0xFFu, /* SDD0_IN = 15 */
|
||||
|
||||
0xFFu, /* ADC1_1P5V = 16 */
|
||||
2u, /* ABPS4 = 17 */
|
||||
2u, /* ABPS5 = 18 */
|
||||
2u, /* CM2 = 19 */
|
||||
2u, /* TM2 = 20 */
|
||||
3u, /* ABPS6 = 21 */
|
||||
3u, /* ABPS7 = 22 */
|
||||
3u, /* CM3 = 23 */
|
||||
3u, /* TM3 = 24 */
|
||||
0xFFu, /* ADC4 = 25 */
|
||||
0xFFu, /* ADC5 = 26 */
|
||||
0xFFu, /* ADC6 = 27 */
|
||||
0xFFu, /* ADC7 = 28 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
0xFFu, /* SDD1_IN = 31 */
|
||||
|
||||
0xFFu, /* ADC2_1P5V = 32 */
|
||||
4u, /* ABPS8 = 33 */
|
||||
4u, /* ABPS9 = 34 */
|
||||
4u, /* CM4 = 35 */
|
||||
4u, /* TM4 = 36 */
|
||||
5u, /* ABPS10 = 37 */
|
||||
5u, /* ABPS11 = 38 */
|
||||
5u, /* CM5 = 39 */
|
||||
5u, /* TM5 = 40 */
|
||||
0xFFu, /* ADC8 = 41 */
|
||||
0xFFu, /* ADC9 = 42 */
|
||||
0xFFu, /* ADC10 = 43 */
|
||||
0xFFu, /* ADC11 = 44 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
0xFFu /* SDD2_IN = 47 */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
#define NON_ABPS_CHANNEL 0xFFu
|
||||
#define MAX_NB_OF_APBS 12u
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* Lookup of the quad to which an ABPS belongs
|
||||
*/
|
||||
static const uint8_t abps_channel_lut[] =
|
||||
{
|
||||
NON_ABPS_CHANNEL, /* ADC0_1P5V = 0 */
|
||||
0u, /* ABPS0 = 1 */
|
||||
0u, /* ABPS1 = 2 */
|
||||
NON_ABPS_CHANNEL, /* CM0 = 3 */
|
||||
NON_ABPS_CHANNEL, /* TM0 = 4 */
|
||||
1u, /* ABPS2 = 5 */
|
||||
1u, /* ABPS3 = 6 */
|
||||
NON_ABPS_CHANNEL, /* CM1 = 7 */
|
||||
NON_ABPS_CHANNEL, /* TM1 = 8 */
|
||||
NON_ABPS_CHANNEL, /* ADC0 = 9 */
|
||||
NON_ABPS_CHANNEL, /* ADC1 = 10 */
|
||||
NON_ABPS_CHANNEL, /* ADC2 = 11 */
|
||||
NON_ABPS_CHANNEL, /* ADC3 = 12 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
NON_ABPS_CHANNEL, /* SDD0_IN = 15 */
|
||||
|
||||
NON_ABPS_CHANNEL, /* ADC1_1P5V = 16 */
|
||||
2u, /* ABPS4 = 17 */
|
||||
2u, /* ABPS5 = 18 */
|
||||
NON_ABPS_CHANNEL, /* CM2 = 19 */
|
||||
NON_ABPS_CHANNEL, /* TM2 = 20 */
|
||||
3u, /* ABPS6 = 21 */
|
||||
3u, /* ABPS7 = 22 */
|
||||
NON_ABPS_CHANNEL, /* CM3 = 23 */
|
||||
NON_ABPS_CHANNEL, /* TM3 = 24 */
|
||||
NON_ABPS_CHANNEL, /* ADC4 = 25 */
|
||||
NON_ABPS_CHANNEL, /* ADC5 = 26 */
|
||||
NON_ABPS_CHANNEL, /* ADC6 = 27 */
|
||||
NON_ABPS_CHANNEL, /* ADC7 = 28 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
NON_ABPS_CHANNEL, /* SDD1_IN = 31 */
|
||||
|
||||
NON_ABPS_CHANNEL, /* ADC2_1P5V = 32 */
|
||||
4u, /* ABPS8 = 33 */
|
||||
4u, /* ABPS9 = 34 */
|
||||
NON_ABPS_CHANNEL, /* CM4 = 35 */
|
||||
NON_ABPS_CHANNEL, /* TM4 = 36 */
|
||||
5u, /* ABPS10 = 37 */
|
||||
5u, /* ABPS11 = 38 */
|
||||
NON_ABPS_CHANNEL, /* CM5 = 39 */
|
||||
NON_ABPS_CHANNEL, /* TM5 = 40 */
|
||||
NON_ABPS_CHANNEL, /* ADC8 = 41 */
|
||||
NON_ABPS_CHANNEL, /* ADC9 = 42 */
|
||||
NON_ABPS_CHANNEL, /* ADC10 = 43 */
|
||||
NON_ABPS_CHANNEL, /* ADC11 = 44 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
NON_ABPS_CHANNEL /* SDD2_IN = 47 */
|
||||
};
|
||||
|
||||
static const uint8_t abps_idx_lut[] =
|
||||
{
|
||||
NON_ABPS_CHANNEL, /* ADC0_1P5V = 0 */
|
||||
0u, /* ABPS0 = 1 */
|
||||
1u, /* ABPS1 = 2 */
|
||||
NON_ABPS_CHANNEL, /* CM0 = 3 */
|
||||
NON_ABPS_CHANNEL, /* TM0 = 4 */
|
||||
2u, /* ABPS2 = 5 */
|
||||
3u, /* ABPS3 = 6 */
|
||||
NON_ABPS_CHANNEL, /* CM1 = 7 */
|
||||
NON_ABPS_CHANNEL, /* TM1 = 8 */
|
||||
NON_ABPS_CHANNEL, /* ADC0 = 9 */
|
||||
NON_ABPS_CHANNEL, /* ADC1 = 10 */
|
||||
NON_ABPS_CHANNEL, /* ADC2 = 11 */
|
||||
NON_ABPS_CHANNEL, /* ADC3 = 12 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
NON_ABPS_CHANNEL, /* SDD0_IN = 15 */
|
||||
|
||||
NON_ABPS_CHANNEL, /* ADC1_1P5V = 16 */
|
||||
4u, /* ABPS4 = 17 */
|
||||
5u, /* ABPS5 = 18 */
|
||||
NON_ABPS_CHANNEL, /* CM2 = 19 */
|
||||
NON_ABPS_CHANNEL, /* TM2 = 20 */
|
||||
6u, /* ABPS6 = 21 */
|
||||
7u, /* ABPS7 = 22 */
|
||||
NON_ABPS_CHANNEL, /* CM3 = 23 */
|
||||
NON_ABPS_CHANNEL, /* TM3 = 24 */
|
||||
NON_ABPS_CHANNEL, /* ADC4 = 25 */
|
||||
NON_ABPS_CHANNEL, /* ADC5 = 26 */
|
||||
NON_ABPS_CHANNEL, /* ADC6 = 27 */
|
||||
NON_ABPS_CHANNEL, /* ADC7 = 28 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
NON_ABPS_CHANNEL, /* SDD1_IN = 31 */
|
||||
|
||||
NON_ABPS_CHANNEL, /* ADC2_1P5V = 32 */
|
||||
8u, /* ABPS8 = 33 */
|
||||
9u, /* ABPS9 = 34 */
|
||||
NON_ABPS_CHANNEL, /* CM4 = 35 */
|
||||
NON_ABPS_CHANNEL, /* TM4 = 36 */
|
||||
10u, /* ABPS10 = 37 */
|
||||
11u, /* ABPS11 = 38 */
|
||||
NON_ABPS_CHANNEL, /* CM5 = 39 */
|
||||
NON_ABPS_CHANNEL, /* TM5 = 40 */
|
||||
NON_ABPS_CHANNEL, /* ADC8 = 41 */
|
||||
NON_ABPS_CHANNEL, /* ADC9 = 42 */
|
||||
NON_ABPS_CHANNEL, /* ADC10 = 43 */
|
||||
NON_ABPS_CHANNEL, /* ADC11 = 44 */
|
||||
INVALID_CHANNEL,
|
||||
INVALID_CHANNEL,
|
||||
NON_ABPS_CHANNEL /* SDD2_IN = 47 */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
static const int8_t apbs_gain_lut[] =
|
||||
{
|
||||
12,
|
||||
8,
|
||||
4,
|
||||
2
|
||||
};
|
||||
|
||||
static const int16_t apbs_range[] =
|
||||
{
|
||||
15360,
|
||||
10240,
|
||||
5120,
|
||||
2560
|
||||
};
|
||||
|
||||
static uint8_t g_gdec_lut[MAX_NB_OF_APBS];
|
||||
static channel_type_t channel_type_lut_h[ACE_NB_OF_INPUT_CHANNELS];
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
channel_type_t
|
||||
ACE_get_channel_type
|
||||
(
|
||||
ace_channel_handle_t channel_handle
|
||||
)
|
||||
{
|
||||
channel_type_t channel_type = VOLTAGE;
|
||||
|
||||
ASSERT(channel_handle < ACE_NB_OF_INPUT_CHANNELS);
|
||||
|
||||
if((int32_t)channel_handle < ACE_NB_OF_INPUT_CHANNELS)
|
||||
{
|
||||
channel_type = channel_type_lut_h[channel_handle];
|
||||
}
|
||||
else
|
||||
{
|
||||
channel_type = VOLTAGE;
|
||||
}
|
||||
|
||||
return channel_type;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint32_t ACE_convert_adc_input_to_mV
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint16_t sample_value
|
||||
)
|
||||
{
|
||||
uint32_t voltage;
|
||||
adc_channel_id_t channel_id;
|
||||
uint8_t adc_id;
|
||||
|
||||
channel_id = g_ace_channel_desc_table[channel_handle].signal_id;
|
||||
adc_id = (uint8_t)channel_id >> 4u;
|
||||
voltage = ( g_ace_adc_config[adc_id].va_ref * (uint32_t)sample_value ) / g_ace_adc_config[adc_id].adc_resolution;
|
||||
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
#define PPE_SAMPLES_RESOLUTION 4095u
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ace_init_convert(void)
|
||||
{
|
||||
uint8_t abps_idx;
|
||||
int32_t channel;
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
/* Populate the g_gdec_lut look-up table. */
|
||||
for(abps_idx = 0u; abps_idx < MAX_NB_OF_APBS; ++abps_idx)
|
||||
{
|
||||
uint8_t quad_id;
|
||||
uint8_t acb_config_byte;
|
||||
uint32_t channel_is_abps2;
|
||||
|
||||
quad_id = abps_idx / 2u;
|
||||
acb_config_byte = ACE->ACB_DATA[quad_id].b8;
|
||||
channel_is_abps2 = abps_idx & 0x01uL;
|
||||
if(channel_is_abps2)
|
||||
{
|
||||
/* ABPS2 */
|
||||
g_gdec_lut[abps_idx] = (acb_config_byte >> 5u) & 0x03u;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ABPS1 */
|
||||
g_gdec_lut[abps_idx] = (acb_config_byte >> 1u) & 0x03u;
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the channel_type_lut_h look-up table. */
|
||||
for(channel = 0; channel < ACE_NB_OF_INPUT_CHANNELS; ++channel)
|
||||
{
|
||||
uint8_t quad_id;
|
||||
uint8_t acb_config_byte;
|
||||
adc_channel_id_t channel_id;
|
||||
channel_type_t channel_type;
|
||||
|
||||
channel_id = g_ace_channel_desc_table[channel].signal_id;
|
||||
quad_id = channel_quad_lut[channel_id];
|
||||
|
||||
switch (channel_type_lut[channel_id])
|
||||
{
|
||||
case VOLTAGE_CHANNEL:
|
||||
channel_type = VOLTAGE;
|
||||
break;
|
||||
|
||||
case CURRENT_CHANNEL:
|
||||
ASSERT( quad_id != 0xFFu );
|
||||
acb_config_byte = ACE->ACB_DATA[quad_id].b9;
|
||||
if ( acb_config_byte & 0x01u )
|
||||
{
|
||||
channel_type = VOLTAGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel_type = CURRENT;
|
||||
}
|
||||
break;
|
||||
|
||||
case TEMPERATURE_CHANNEL:
|
||||
ASSERT( quad_id != 0xFFu );
|
||||
acb_config_byte = ACE->ACB_DATA[quad_id].b10;
|
||||
if ( acb_config_byte & 0x01u )
|
||||
{
|
||||
channel_type = VOLTAGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel_type = TEMPERATURE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
channel_type = VOLTAGE;
|
||||
break;
|
||||
}
|
||||
|
||||
channel_type_lut_h[channel] = channel_type;
|
||||
}
|
||||
|
||||
/* Restore SSE PC2 operations. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
int32_t ACE_convert_to_mV
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint16_t sample_value
|
||||
)
|
||||
{
|
||||
uint32_t adc_voltage;
|
||||
int32_t voltage;
|
||||
adc_channel_id_t channel_id;
|
||||
uint8_t adc_id;
|
||||
uint8_t apbs_idx;
|
||||
|
||||
channel_id = g_ace_channel_desc_table[channel_handle].signal_id;
|
||||
adc_id = (uint8_t)channel_id >> 4u;
|
||||
adc_voltage = ( g_ace_adc_config[adc_id].va_ref * (uint32_t)sample_value ) / PPE_SAMPLES_RESOLUTION;
|
||||
voltage = (int32_t)adc_voltage;
|
||||
|
||||
apbs_idx = abps_idx_lut[channel_id];
|
||||
if ( abps_channel_lut[channel_id] != NON_ABPS_CHANNEL )
|
||||
{
|
||||
uint8_t gdec;
|
||||
gdec = g_gdec_lut[apbs_idx];
|
||||
voltage = (voltage * apbs_gain_lut[gdec]) - apbs_range[gdec];
|
||||
}
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint32_t ACE_convert_to_mA
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint16_t sample_value
|
||||
)
|
||||
{
|
||||
uint32_t current = 0u;
|
||||
|
||||
ASSERT(channel_handle < ACE_NB_OF_INPUT_CHANNELS);
|
||||
|
||||
if((int32_t)channel_handle < ACE_NB_OF_INPUT_CHANNELS)
|
||||
{
|
||||
adc_channel_id_t channel_id;
|
||||
uint8_t current_monitor_idx;
|
||||
|
||||
channel_id = g_ace_channel_desc_table[channel_handle].signal_id;
|
||||
ASSERT(channel_id < sizeof(channel_type_lut));
|
||||
if(CURRENT_CHANNEL == channel_type_lut[channel_id])
|
||||
{
|
||||
uint32_t resistor;
|
||||
uint32_t voltage;
|
||||
|
||||
/* Compute index into g_ace_current_resistors[] from the current
|
||||
* channel number. This uses bit 2, 4 and 5 of the channel number
|
||||
* to derive the index as follows:
|
||||
* channel name : channel number : index
|
||||
* CM0 : 0x03 : 0
|
||||
* CM1 : 0x07 : 1
|
||||
* CM2 : 0x13 : 2
|
||||
* CM3 : 0x17 : 3
|
||||
* CM4 : 0x23 : 4
|
||||
* CM5 : 0x27 : 5
|
||||
*/
|
||||
current_monitor_idx
|
||||
= (((uint8_t)channel_id & 0x04u) >> 2u) + (((uint8_t)channel_id & 0x30u) >> 3u);
|
||||
|
||||
if(current_monitor_idx < (uint8_t)ACE_NB_OF_CURRENT_MONITORS)
|
||||
{
|
||||
/* Retrieve the current sensing external resistor value from
|
||||
* the ACE configuration data generated by the ACE configurator. */
|
||||
resistor = g_ace_current_resistors[current_monitor_idx];
|
||||
|
||||
/* Compute mA current value taking into account the amplication
|
||||
* factor of 50 used within the current monitor hardware. */
|
||||
voltage = ACE_convert_adc_input_to_mV(channel_handle, sample_value);
|
||||
current = (voltage * (1000u / 50u)) / resistor;
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint32_t ACE_convert_to_Kelvin
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint16_t sample_value
|
||||
)
|
||||
{
|
||||
uint32_t temperature;
|
||||
uint32_t voltage;
|
||||
|
||||
voltage = ACE_convert_adc_input_to_mV( channel_handle, sample_value );
|
||||
|
||||
/* Tk = (V * 10^3) / 2.5 */
|
||||
temperature = (voltage * 10u) / 25u;
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
int32_t ACE_convert_to_Celsius
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint16_t sample_value
|
||||
)
|
||||
{
|
||||
int32_t temperature;
|
||||
int32_t voltage;
|
||||
|
||||
voltage = (int32_t)ACE_convert_adc_input_to_mV( channel_handle, sample_value );
|
||||
|
||||
/* Tk = (V * 10^3) / 2.5 */
|
||||
/* Tc = Tk - 273.15 */
|
||||
temperature = (voltage * 4) - 2731;
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
int32_t ACE_convert_to_Fahrenheit
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint16_t sample_value
|
||||
)
|
||||
{
|
||||
int32_t temperature;
|
||||
|
||||
temperature = (int32_t)ACE_convert_to_Kelvin( channel_handle, sample_value );
|
||||
|
||||
/* F = (K * 9/5) - 459.67 */
|
||||
temperature = ((temperature * 9) / 5) - 459;
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
const uint8_t * ACE_get_channel_name
|
||||
(
|
||||
ace_channel_handle_t channel_handle
|
||||
)
|
||||
{
|
||||
const uint8_t * p_channel_name = 0;
|
||||
|
||||
if ( channel_handle < NB_OF_ACE_CHANNEL_HANDLES)
|
||||
{
|
||||
p_channel_name = g_ace_channel_desc_table[channel_handle].p_sz_channel_name;
|
||||
}
|
||||
|
||||
return p_channel_name;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint16_t ACE_convert_mV_to_adc_value
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint32_t voltage
|
||||
)
|
||||
{
|
||||
uint16_t sample_value;
|
||||
adc_channel_id_t channel_id;
|
||||
uint8_t adc_id;
|
||||
|
||||
channel_id = g_ace_channel_desc_table[channel_handle].signal_id;
|
||||
adc_id = (uint8_t)channel_id >> 4u;
|
||||
|
||||
if (voltage > g_ace_adc_config[adc_id].va_ref)
|
||||
{
|
||||
sample_value = g_ace_adc_config[adc_id].adc_resolution - 1u;
|
||||
}
|
||||
else
|
||||
{
|
||||
sample_value = (uint16_t)((voltage * (g_ace_adc_config[adc_id].adc_resolution - 1)) / g_ace_adc_config[adc_id].va_ref);
|
||||
}
|
||||
|
||||
return sample_value;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
static uint16_t convert_mV_to_ppe_value
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint32_t voltage
|
||||
)
|
||||
{
|
||||
uint16_t sample_value;
|
||||
adc_channel_id_t channel_id;
|
||||
uint8_t adc_id;
|
||||
|
||||
channel_id = g_ace_channel_desc_table[channel_handle].signal_id;
|
||||
adc_id = (uint8_t)channel_id >> 4u;
|
||||
|
||||
if (voltage > g_ace_adc_config[adc_id].va_ref)
|
||||
{
|
||||
sample_value = PPE_SAMPLES_RESOLUTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
sample_value = (uint16_t)((voltage * PPE_SAMPLES_RESOLUTION) / g_ace_adc_config[adc_id].va_ref);
|
||||
}
|
||||
|
||||
return sample_value;
|
||||
}
|
||||
|
||||
#define MAX_PPE_SAMPLE_VALUE 0x0FFFu
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint16_t ACE_convert_from_mV
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
int32_t voltage
|
||||
)
|
||||
{
|
||||
uint16_t sample_value;
|
||||
adc_channel_id_t channel_id;
|
||||
uint8_t adc_id;
|
||||
uint32_t adc_voltage;
|
||||
|
||||
channel_id = g_ace_channel_desc_table[channel_handle].signal_id;
|
||||
adc_id = (uint8_t)channel_id >> 4u;
|
||||
|
||||
if ( abps_channel_lut[channel_id] == NON_ABPS_CHANNEL )
|
||||
{
|
||||
if (voltage > 0)
|
||||
{
|
||||
adc_voltage = (uint32_t)voltage;
|
||||
}
|
||||
else
|
||||
{
|
||||
adc_voltage = 0u;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t apbs_idx;
|
||||
uint8_t gdec;
|
||||
|
||||
apbs_idx = abps_idx_lut[channel_id];
|
||||
gdec = g_gdec_lut[apbs_idx];
|
||||
voltage = voltage + apbs_range[gdec];
|
||||
if (voltage > 0)
|
||||
{
|
||||
adc_voltage = (uint32_t)voltage;
|
||||
adc_voltage = adc_voltage / (uint8_t)apbs_gain_lut[gdec];
|
||||
}
|
||||
else
|
||||
{
|
||||
adc_voltage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sample_value = (uint16_t)((adc_voltage * PPE_SAMPLES_RESOLUTION) / g_ace_adc_config[adc_id].va_ref);
|
||||
|
||||
if (sample_value > MAX_PPE_SAMPLE_VALUE)
|
||||
{
|
||||
sample_value = MAX_PPE_SAMPLE_VALUE;
|
||||
}
|
||||
return sample_value;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint16_t ACE_convert_from_mA
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint32_t current
|
||||
)
|
||||
{
|
||||
uint16_t sample_value;
|
||||
uint32_t voltage;
|
||||
uint32_t resistor = 1u;
|
||||
|
||||
voltage = current * 50u * resistor;
|
||||
sample_value = convert_mV_to_ppe_value( channel_handle, voltage );
|
||||
|
||||
if (sample_value > MAX_PPE_SAMPLE_VALUE)
|
||||
{
|
||||
sample_value = MAX_PPE_SAMPLE_VALUE;
|
||||
}
|
||||
return sample_value;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint16_t ACE_convert_from_Kelvin
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint32_t temperature
|
||||
)
|
||||
{
|
||||
uint16_t sample_value;
|
||||
uint32_t voltage;
|
||||
|
||||
voltage = (temperature * 25u) / 10u;
|
||||
sample_value = convert_mV_to_ppe_value( channel_handle, voltage );
|
||||
|
||||
if (sample_value > MAX_PPE_SAMPLE_VALUE)
|
||||
{
|
||||
sample_value = MAX_PPE_SAMPLE_VALUE;
|
||||
}
|
||||
return sample_value;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint16_t ACE_convert_from_Celsius
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
int32_t temperature
|
||||
)
|
||||
{
|
||||
uint16_t sample_value;
|
||||
uint32_t voltage;
|
||||
|
||||
temperature = temperature + 2731;
|
||||
voltage = (uint32_t)temperature / 4u;
|
||||
sample_value = convert_mV_to_ppe_value( channel_handle, voltage );
|
||||
|
||||
if (sample_value > MAX_PPE_SAMPLE_VALUE)
|
||||
{
|
||||
sample_value = MAX_PPE_SAMPLE_VALUE;
|
||||
}
|
||||
return sample_value;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint16_t ACE_convert_from_Fahrenheit
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
int32_t temperature
|
||||
)
|
||||
{
|
||||
uint16_t sample_value;
|
||||
uint32_t kelvin;
|
||||
|
||||
temperature = temperature + 459;
|
||||
kelvin = (uint32_t)temperature;
|
||||
kelvin = (kelvin * 5u) / 9u;
|
||||
|
||||
sample_value = ACE_convert_from_Kelvin( channel_handle, kelvin );
|
||||
|
||||
if (sample_value > MAX_PPE_SAMPLE_VALUE)
|
||||
{
|
||||
sample_value = MAX_PPE_SAMPLE_VALUE;
|
||||
}
|
||||
return sample_value;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
uint16_t ACE_translate_pdma_value
|
||||
(
|
||||
uint32_t pdma_value,
|
||||
adc_channel_id_t * channel_id
|
||||
)
|
||||
{
|
||||
uint16_t ppe_value;
|
||||
|
||||
ppe_value = (pdma_value >> 8u) & 0xFFFFu;
|
||||
if ( channel_id != 0 )
|
||||
{
|
||||
*channel_id = (adc_channel_id_t)((pdma_value >> 24u) & 0xFFu);
|
||||
}
|
||||
|
||||
return ppe_value;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,306 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SVN $Revision: 2905 $
|
||||
* SVN $Date: 2010-08-20 14:03:28 +0100 (Fri, 20 Aug 2010) $
|
||||
*/
|
||||
#include "mss_ace.h"
|
||||
#include "mss_ace_configurator.h"
|
||||
#include "../../drivers_config/mss_ace/ace_handles.h"
|
||||
#include "../../drivers_config/mss_ace/ace_config.h"
|
||||
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SSE_START 1uL
|
||||
#define SSE_STOP 0uL
|
||||
|
||||
#define NB_OF_ANALOG_BLOCKS 3u
|
||||
#define SEE_RAM_WORD_SIZE 512
|
||||
|
||||
#define TS_ENABLE_MASK 0x01u
|
||||
#define PPE_ENABLE_MASK 0x01u
|
||||
#define ADC_RESET_MASK 0x10u
|
||||
#define ADC_FIFO_CLR_MASK 0x04u
|
||||
#define PDMA_DATAOUT_CLR_MASK 0x04u
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
extern ace_procedure_desc_t g_sse_sequences_desc_table[ACE_NB_OF_SSE_PROCEDURES];
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
sse_sequence_handle_t
|
||||
ACE_get_sse_seq_handle
|
||||
(
|
||||
const uint8_t * p_sz_sequence_name
|
||||
)
|
||||
{
|
||||
uint16_t seq_idx;
|
||||
sse_sequence_handle_t handle = INVALID_SSE_SEQ_HANDLE;
|
||||
|
||||
for ( seq_idx = 0u; seq_idx < (uint32_t)ACE_NB_OF_SSE_PROCEDURES; ++seq_idx )
|
||||
{
|
||||
if ( g_sse_sequences_desc_table[seq_idx].p_sz_proc_name != 0 )
|
||||
{
|
||||
int32_t diff;
|
||||
diff = strncmp( (const char *)p_sz_sequence_name, (const char *)g_sse_sequences_desc_table[seq_idx].p_sz_proc_name, MAX_PROCEDURE_NAME_LENGTH );
|
||||
if ( 0 == diff )
|
||||
{
|
||||
/* channel name found. */
|
||||
handle = seq_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
static uint32_t volatile * const sse_pc_ctrl_lut[NB_OF_ANALOG_BLOCKS] =
|
||||
{
|
||||
&ACE->PC0_CTRL,
|
||||
&ACE->PC1_CTRL,
|
||||
&ACE->PC2_CTRL
|
||||
};
|
||||
|
||||
static uint32_t volatile * const sse_pc_lo_lut[NB_OF_ANALOG_BLOCKS] =
|
||||
{
|
||||
&ACE->PC0_LO,
|
||||
&ACE->PC1_LO,
|
||||
&ACE->PC2_LO
|
||||
};
|
||||
|
||||
static uint32_t volatile * const sse_pc_hi_lut[NB_OF_ANALOG_BLOCKS] =
|
||||
{
|
||||
&ACE->PC0_HI,
|
||||
&ACE->PC1_HI,
|
||||
&ACE->PC2_HI
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_load_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t offset;
|
||||
const uint16_t * p_ucode;
|
||||
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_pc_id < NB_OF_ANALOG_BLOCKS );
|
||||
|
||||
if ( g_sse_sequences_desc_table[sequence].sse_pc_id < NB_OF_ANALOG_BLOCKS )
|
||||
{
|
||||
/* Stop relevant program counter. */
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_STOP;
|
||||
|
||||
/* Load microcode into SEE RAM.*/
|
||||
p_ucode = g_sse_sequences_desc_table[sequence].sse_ucode;
|
||||
offset = g_sse_sequences_desc_table[sequence].sse_load_offset;
|
||||
|
||||
for ( i = 0u; i < g_sse_sequences_desc_table[sequence].sse_ucode_length; ++i )
|
||||
{
|
||||
ACE->SSE_RAM_DATA[offset + i] = (uint32_t)*p_ucode;
|
||||
++p_ucode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_start_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
uint16_t pc;
|
||||
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_pc_id < NB_OF_ANALOG_BLOCKS );
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_load_offset < SEE_RAM_WORD_SIZE );
|
||||
|
||||
pc = g_sse_sequences_desc_table[sequence].sse_load_offset;
|
||||
|
||||
if ( pc < 256u )
|
||||
{
|
||||
*sse_pc_lo_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = pc;
|
||||
}
|
||||
else
|
||||
{
|
||||
*sse_pc_hi_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = pc - 256;
|
||||
}
|
||||
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_START;
|
||||
|
||||
/* Enable Sample Sequencing Engine in case it was not done as part of
|
||||
* system boot. */
|
||||
ACE->SSE_TS_CTRL |= TS_ENABLE_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_restart_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < ACE_NB_OF_SSE_PROCEDURES );
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_pc_id < NB_OF_ANALOG_BLOCKS );
|
||||
ASSERT( g_sse_sequences_desc_table[sequence].sse_load_offset < SEE_RAM_WORD_SIZE );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
uint16_t pc;
|
||||
|
||||
pc = g_sse_sequences_desc_table[sequence].sse_loop_pc;
|
||||
|
||||
if ( pc < 256u )
|
||||
{
|
||||
*sse_pc_lo_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = pc;
|
||||
}
|
||||
else
|
||||
{
|
||||
*sse_pc_hi_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = pc - 256;
|
||||
}
|
||||
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_START;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_stop_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < ACE_NB_OF_SSE_PROCEDURES );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
/* Stop relevant program counter. */
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_resume_sse
|
||||
(
|
||||
sse_sequence_handle_t sequence
|
||||
)
|
||||
{
|
||||
ASSERT( sequence < ACE_NB_OF_SSE_PROCEDURES );
|
||||
|
||||
if ( sequence < (sse_sequence_handle_t)ACE_NB_OF_SSE_PROCEDURES )
|
||||
{
|
||||
*sse_pc_ctrl_lut[g_sse_sequences_desc_table[sequence].sse_pc_id] = SSE_START;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_enable_sse_irq
|
||||
(
|
||||
sse_irq_id_t sse_irq_id
|
||||
)
|
||||
{
|
||||
ASSERT( sse_irq_id < NB_OF_SSE_FLAG_IRQS );
|
||||
|
||||
ACE->SSE_IRQ_EN |= 1uL << (uint32_t)sse_irq_id;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_disable_sse_irq
|
||||
(
|
||||
sse_irq_id_t sse_irq_id
|
||||
)
|
||||
{
|
||||
ASSERT( sse_irq_id < NB_OF_SSE_FLAG_IRQS );
|
||||
|
||||
ACE->SSE_IRQ_EN &= (uint32_t)~(1uL << (uint32_t)sse_irq_id);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_clear_sse_irq
|
||||
(
|
||||
sse_irq_id_t sse_irq_id
|
||||
)
|
||||
{
|
||||
ASSERT( sse_irq_id < NB_OF_SSE_FLAG_IRQS );
|
||||
|
||||
ACE->SSE_IRQ_CLR |= 1uL << (uint32_t)sse_irq_id;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_clear_sample_pipeline(void)
|
||||
{
|
||||
uint32_t saved_sse_ctrl;
|
||||
uint32_t saved_ppe_ctrl;
|
||||
|
||||
/* Pause the Sample Sequencing Engine. */
|
||||
saved_sse_ctrl = ACE->SSE_TS_CTRL;
|
||||
ACE->SSE_TS_CTRL = ACE->SSE_TS_CTRL & ~((uint32_t)TS_ENABLE_MASK);
|
||||
|
||||
/* Pause the Post Processing Engine. */
|
||||
saved_ppe_ctrl = ACE->PPE_CTRL;
|
||||
ACE->PPE_CTRL = ACE->PPE_CTRL & ~((uint32_t)PPE_ENABLE_MASK);
|
||||
|
||||
/* Reset the ADCs */
|
||||
ACE->ADC0_MISC_CTRL |= ADC_RESET_MASK;
|
||||
ACE->ADC1_MISC_CTRL |= ADC_RESET_MASK;
|
||||
ACE->ADC2_MISC_CTRL |= ADC_RESET_MASK;
|
||||
|
||||
/* Clear ADC FIFOs */
|
||||
ACE->ADC0_FIFO_CTRL |= ADC_FIFO_CLR_MASK;
|
||||
ACE->ADC1_FIFO_CTRL |= ADC_FIFO_CLR_MASK;
|
||||
ACE->ADC2_FIFO_CTRL |= ADC_FIFO_CLR_MASK;
|
||||
|
||||
/* clear DMA FIFOs */
|
||||
ACE->PPE_PDMA_CTRL |= PDMA_DATAOUT_CLR_MASK;
|
||||
|
||||
/* Unpause the Post Processing Engine. */
|
||||
ACE->PPE_CTRL = saved_ppe_ctrl;
|
||||
|
||||
/* Unpause the Sample Sequencing Engine. */
|
||||
ACE->SSE_TS_CTRL = saved_sse_ctrl;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,467 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2010 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* This file contains the implementation of the functions used to dynamically
|
||||
* control the linear transforms applied by the ACE post processing engine to
|
||||
* the samples read from the SSE.
|
||||
*
|
||||
* SVN $Revision: 2908 $
|
||||
* SVN $Date: 2010-08-20 16:01:28 +0100 (Fri, 20 Aug 2010) $
|
||||
*/
|
||||
|
||||
#include "mss_ace.h"
|
||||
#include "mss_ace_configurator.h"
|
||||
#include "mtd_data.h"
|
||||
#include "envm_layout.h"
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
#include "../../drivers_config/mss_ace/ace_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The ACE_set_linear_transform() is only available when using ACE configuration
|
||||
* files generated by Libero 9.1 or later.
|
||||
*/
|
||||
#ifdef ACE_CFG_DATA_FORMAT_VERSION
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Masks ans shift values used to derive the ABPS ranges from the analog block
|
||||
* configuration.
|
||||
*/
|
||||
#define ABPS1_CFG_BITS_MASK (uint32_t)0x06
|
||||
#define ABPS1_CFG_BITS_SHIFT (uint32_t)1
|
||||
|
||||
#define ABPS2_CFG_BITS_MASK (uint32_t)0x60
|
||||
#define ABPS2_CFG_BITS_SHIFT (uint32_t)5
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* One Bit DAC definitions.
|
||||
*/
|
||||
#define OBD_CURRENT (uint32_t)1
|
||||
#define OBD_VOLTAGE (uint32_t)0
|
||||
|
||||
#define OBD_MODE_MASK (uint32_t)0x01
|
||||
#define OBD_CHOPPING_MASK (uint32_t)0x02
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Neutral factor and offset for m*x + c trnasform.
|
||||
*/
|
||||
#define NEUTRAL_M_FACTOR 0x4000
|
||||
#define NEUTRAL_C_OFFSET 0x0000
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Enumearation of the various input channel types. This is used to differentiate
|
||||
between channel types in order to extract the relevant factory calibration
|
||||
data(m1 and c1).
|
||||
*/
|
||||
typedef enum channel_type
|
||||
{
|
||||
ABPS1_CHAN = 0,
|
||||
ABPS2_CHAN,
|
||||
CMB_CHAN,
|
||||
TMB_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
OBDOUT_CHAN,
|
||||
FLOATING_CHAN
|
||||
} cal_channel_type_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
This data structure is used to store factory calibration data for a specific
|
||||
analog input.
|
||||
*/
|
||||
typedef struct __channel_calibration_t
|
||||
{
|
||||
uint16_t mext;
|
||||
uint16_t m1;
|
||||
uint16_t c1;
|
||||
} channel_calibration_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Local functions
|
||||
*/
|
||||
int32_t extend_sign
|
||||
(
|
||||
uint16_t x
|
||||
);
|
||||
|
||||
uint32_t adjust_to_24bit_ace_format
|
||||
(
|
||||
int64_t signed48
|
||||
);
|
||||
|
||||
uint32_t adjust_to_16bit_ace_format
|
||||
(
|
||||
int64_t signed48
|
||||
);
|
||||
|
||||
void get_calibration
|
||||
(
|
||||
adc_channel_id_t channel_id,
|
||||
channel_calibration_t * p_calibration
|
||||
);
|
||||
|
||||
void write_transform_coefficients
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint32_t m,
|
||||
uint32_t c
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
|
||||
*/
|
||||
extern const uint8_t g_ace_external_varef_used[ACE_NB_OF_ADC];
|
||||
|
||||
extern ace_channel_desc_t g_ace_channel_desc_table[ACE_NB_OF_INPUT_CHANNELS];
|
||||
|
||||
extern const ppe_transforms_desc_t g_ace_ppe_transforms_desc_table[ACE_NB_OF_INPUT_CHANNELS];
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Pointer to the manufacturing test data containing trimming information
|
||||
* generated during manufacturing.
|
||||
*/
|
||||
static const mtd_data_t * const p_mtd_data = (mtd_data_t *)MTD_ADDRESS;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
int16_t ACE_get_default_m_factor
|
||||
(
|
||||
ace_channel_handle_t channel_handle
|
||||
)
|
||||
{
|
||||
ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );
|
||||
|
||||
return g_ace_ppe_transforms_desc_table[channel_handle].m_ppe_offset;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
int16_t ACE_get_default_c_offset
|
||||
(
|
||||
ace_channel_handle_t channel_handle
|
||||
)
|
||||
{
|
||||
ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );
|
||||
|
||||
return g_ace_ppe_transforms_desc_table[channel_handle].c_ppe_offset;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
|
||||
m = m2 * m1 * mext
|
||||
c = (m2 * c1 * mext) + (c2 * mext)
|
||||
*/
|
||||
void ACE_set_linear_transform
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
int16_t m2,
|
||||
int16_t c2
|
||||
)
|
||||
{
|
||||
adc_channel_id_t channel_id;
|
||||
uint32_t m;
|
||||
uint32_t c;
|
||||
int32_t m32;
|
||||
int64_t m64;
|
||||
int32_t c32;
|
||||
int64_t c64_1;
|
||||
int64_t c64_2;
|
||||
uint16_t m1;
|
||||
uint16_t c1;
|
||||
uint16_t mext;
|
||||
|
||||
channel_calibration_t calibration;
|
||||
|
||||
ASSERT( channel_handle < NB_OF_ACE_CHANNEL_HANDLES );
|
||||
|
||||
if(channel_handle < NB_OF_ACE_CHANNEL_HANDLES)
|
||||
{
|
||||
channel_id = g_ace_channel_desc_table[channel_handle].signal_id;
|
||||
|
||||
get_calibration(channel_id, &calibration);
|
||||
|
||||
m1 = calibration.m1;
|
||||
c1 = calibration.c1;
|
||||
|
||||
mext = calibration.mext;
|
||||
|
||||
/*
|
||||
* m = m2 * m1 * mext
|
||||
*/
|
||||
m32 = extend_sign(m2) * extend_sign(m1);
|
||||
m64 = (int64_t)m32 * extend_sign(mext);
|
||||
|
||||
/* Convert 48-bit result to 32-bit ACE format result. */
|
||||
m = adjust_to_16bit_ace_format(m64);
|
||||
|
||||
/*
|
||||
* c = (m2 * c1 * mext) + (c2 * mext)
|
||||
*/
|
||||
c32 = extend_sign(m2) * extend_sign(c1);
|
||||
c64_1 = (int64_t)c32 * extend_sign(mext);
|
||||
|
||||
c64_2 = ((int64_t)(extend_sign(c2) * extend_sign(mext))) << 14;
|
||||
|
||||
c = adjust_to_24bit_ace_format(c64_1 + c64_2);
|
||||
|
||||
write_transform_coefficients(channel_handle, m, c);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Extend 16-bit signed number to 32-bit signed number.
|
||||
*/
|
||||
int32_t extend_sign
|
||||
(
|
||||
uint16_t x
|
||||
)
|
||||
{
|
||||
int32_t y;
|
||||
const uint32_t sign_bit_mask = 0x00008000u;
|
||||
|
||||
y = (x ^ sign_bit_mask) - sign_bit_mask;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Take a 48-bit signed number, adjust it for saturation in the range -8 to
|
||||
+7.999, translate into 24-bit ACE format.
|
||||
*/
|
||||
uint32_t adjust_to_24bit_ace_format
|
||||
(
|
||||
int64_t signed48
|
||||
)
|
||||
{
|
||||
int32_t ace24_format;
|
||||
const int64_t MAX_POSITIVE = 0x00001FFFFFFFFFFFuLL; /* +7.9999 */
|
||||
const int64_t MIN_NEGATIVE = 0xFFFF200000000000uLL; /* -8 */
|
||||
|
||||
/* Check saturation. */
|
||||
if(signed48 > MAX_POSITIVE)
|
||||
{
|
||||
signed48 = MAX_POSITIVE;
|
||||
}
|
||||
else if(signed48 < MIN_NEGATIVE)
|
||||
{
|
||||
signed48 = MIN_NEGATIVE;
|
||||
}
|
||||
|
||||
/* Adjust to 24-bit ACE format. */
|
||||
ace24_format = (uint32_t)(signed48 >> 14);
|
||||
|
||||
return ace24_format;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Take a 48-bit signed number, adjust it for saturation in the range -8 to
|
||||
+7.999, translate into 16-bit ACE format.
|
||||
*/
|
||||
uint32_t adjust_to_16bit_ace_format
|
||||
(
|
||||
int64_t signed48
|
||||
)
|
||||
{
|
||||
int32_t ace24_format;
|
||||
const int64_t MAX_POSITIVE = 0x00001FFFFFFFFFFFuLL; /* +7.9999 */
|
||||
const int64_t MIN_NEGATIVE = 0xFFFF200000000000uLL; /* -8 */
|
||||
|
||||
/* Check saturation. */
|
||||
if(signed48 > MAX_POSITIVE)
|
||||
{
|
||||
signed48 = MAX_POSITIVE;
|
||||
}
|
||||
else if(signed48 < MIN_NEGATIVE)
|
||||
{
|
||||
signed48 = MIN_NEGATIVE;
|
||||
}
|
||||
|
||||
/* Adjust to 24-bit ACE format. */
|
||||
ace24_format = (uint32_t)(signed48 >> 20);
|
||||
|
||||
return ace24_format;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
|
||||
*/
|
||||
void get_calibration
|
||||
(
|
||||
adc_channel_id_t channel_id,
|
||||
channel_calibration_t * p_calibration
|
||||
)
|
||||
{
|
||||
const uint32_t channel_mask = 0x0000000F;
|
||||
const uint32_t CMB_MUX_SEL_MASK = 0x01;
|
||||
const uint32_t TMB_MUX_SEL_MASK = 0x01;
|
||||
|
||||
const cal_channel_type_t channel_type_lut[16] =
|
||||
{
|
||||
FLOATING_CHAN,
|
||||
ABPS1_CHAN,
|
||||
ABPS2_CHAN,
|
||||
CMB_CHAN,
|
||||
TMB_CHAN,
|
||||
ABPS1_CHAN,
|
||||
ABPS2_CHAN,
|
||||
CMB_CHAN,
|
||||
TMB_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
DIRECT_ADC_INPUT_CHAN,
|
||||
FLOATING_CHAN,
|
||||
FLOATING_CHAN,
|
||||
OBDOUT_CHAN
|
||||
};
|
||||
|
||||
cal_channel_type_t channel_type;
|
||||
uint32_t channel_nb;
|
||||
uint32_t adc_nb;
|
||||
uint32_t range;
|
||||
uint32_t quad_id;
|
||||
mtd_calibration_mc_t const * p_mc_coeff = 0;
|
||||
|
||||
channel_nb = channel_id & channel_mask;
|
||||
channel_type = channel_type_lut[channel_nb];
|
||||
adc_nb = ((uint32_t)channel_id & 0x30u) >> 4u;
|
||||
|
||||
quad_id = adc_nb * 2;
|
||||
|
||||
if ( (channel_nb > 4) && (channel_nb < 9) ) { ++quad_id; }
|
||||
|
||||
switch ( channel_type )
|
||||
{
|
||||
case ABPS1_CHAN:
|
||||
range = (ACE->ACB_DATA[quad_id].b8 & ABPS1_CFG_BITS_MASK) >> ABPS1_CFG_BITS_SHIFT;
|
||||
p_mc_coeff = &p_mtd_data->abps_calibration[quad_id][0][range];
|
||||
break;
|
||||
|
||||
case ABPS2_CHAN:
|
||||
range = (ACE->ACB_DATA[quad_id].b8 & ABPS2_CFG_BITS_MASK) >> ABPS2_CFG_BITS_SHIFT;
|
||||
p_mc_coeff = &p_mtd_data->abps_calibration[quad_id][1][range];
|
||||
break;
|
||||
|
||||
case CMB_CHAN:
|
||||
{
|
||||
uint32_t cmb_mux_sel = (uint32_t)ACE->ACB_DATA[quad_id].b9 & CMB_MUX_SEL_MASK;
|
||||
if ( cmb_mux_sel == 0 )
|
||||
{ /* current monitor */
|
||||
p_mc_coeff = &p_mtd_data->cm_calibration[quad_id];
|
||||
}
|
||||
else
|
||||
{ /* direct input */
|
||||
p_mc_coeff = &p_mtd_data->quads_direct_input_cal[quad_id][0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TMB_CHAN:
|
||||
{
|
||||
uint32_t tmb_mux_sel = (uint32_t)ACE->ACB_DATA[quad_id].b10 & TMB_MUX_SEL_MASK;
|
||||
if ( tmb_mux_sel == 0 )
|
||||
{ /* temperature monitor */
|
||||
p_mc_coeff = &p_mtd_data->tm_calibration[quad_id];
|
||||
}
|
||||
else
|
||||
{ /* direct input */
|
||||
p_mc_coeff = &p_mtd_data->quads_direct_input_cal[quad_id][1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DIRECT_ADC_INPUT_CHAN:
|
||||
{
|
||||
const uint32_t channel_to_direct_in_lut[16]
|
||||
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0};
|
||||
uint32_t direct_in_id;
|
||||
|
||||
direct_in_id = channel_to_direct_in_lut[channel_id & channel_mask];
|
||||
p_mc_coeff = &p_mtd_data->adc_direct_input_cal[adc_nb][direct_in_id];
|
||||
}
|
||||
break;
|
||||
|
||||
case OBDOUT_CHAN:
|
||||
{
|
||||
uint32_t obd_mode = (uint32_t)ACE->ACB_DATA[quad_id].b6 & OBD_MODE_MASK;
|
||||
uint32_t chopping_option = (uint32_t)ACE->ACB_DATA[quad_id].b6 & OBD_CHOPPING_MASK;
|
||||
if (obd_mode > 0)
|
||||
{
|
||||
obd_mode = 1;
|
||||
}
|
||||
if (chopping_option > 0)
|
||||
{
|
||||
chopping_option = 1;
|
||||
}
|
||||
p_mc_coeff = &p_mtd_data->obd_calibration[adc_nb][obd_mode][chopping_option];
|
||||
}
|
||||
break;
|
||||
|
||||
case FLOATING_CHAN:
|
||||
default:
|
||||
/* Give neutral values is invalid channel. */
|
||||
p_calibration->m1 = NEUTRAL_M_FACTOR;
|
||||
p_calibration->c1 = NEUTRAL_C_OFFSET;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_mc_coeff != 0)
|
||||
{
|
||||
p_calibration->m1 = p_mc_coeff->m;
|
||||
p_calibration->c1 = p_mc_coeff->c;
|
||||
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Retrieve the value of the mext factor. This depends if external VAREF is
|
||||
used by the ADC sampling the analog input channel.
|
||||
*/
|
||||
if (g_ace_external_varef_used[adc_nb])
|
||||
{
|
||||
p_calibration->mext = p_mtd_data->global_settings.varef_m;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_calibration->mext = NEUTRAL_M_FACTOR;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Write new m and c transform factors into the PPE RAM. The m and c factors
|
||||
should be in 32-bit ACE number format. The factors will be merged with
|
||||
relevant PE opcode into PPE RAM. The 32-bit factors are shifted right by one
|
||||
byte giving a 24-bit ACE number which is then merged with an 8-bit PPE opcode
|
||||
located in the most significant byte of the PPE RAM location.
|
||||
*/
|
||||
void write_transform_coefficients
|
||||
(
|
||||
ace_channel_handle_t channel_handle,
|
||||
uint32_t m,
|
||||
uint32_t c
|
||||
)
|
||||
{
|
||||
uint16_t m_ppe_offset;
|
||||
uint16_t c_ppe_offset;
|
||||
const uint32_t PPE_OPCODE_MASK = 0xFF000000u;
|
||||
|
||||
m_ppe_offset = g_ace_ppe_transforms_desc_table[channel_handle].m_ppe_offset;
|
||||
c_ppe_offset = g_ace_ppe_transforms_desc_table[channel_handle].c_ppe_offset;
|
||||
|
||||
ACE->PPE_RAM_DATA[m_ppe_offset]
|
||||
= (ACE->PPE_RAM_DATA[m_ppe_offset] & PPE_OPCODE_MASK) | (m >> 8u);
|
||||
|
||||
ACE->PPE_RAM_DATA[c_ppe_offset]
|
||||
= (ACE->PPE_RAM_DATA[c_ppe_offset] & PPE_OPCODE_MASK) | (c >> 8u);
|
||||
}
|
||||
|
||||
#endif /* ACE_CFG_DATA_FORMAT_VERSION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* This file contains the addresses and size of the various blocks of data
|
||||
* stored in eNVM.
|
||||
*
|
||||
* SVN $Revision: 1113 $
|
||||
* SVN $Date: 2009-07-01 11:11:29 +0100 (Wed, 01 Jul 2009) $
|
||||
*/
|
||||
#ifndef ENVM_LAYOUT_HEADER
|
||||
#define ENVM_LAYOUT_HEADER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* Address of the manufacturing test data.
|
||||
*/
|
||||
#define MTD_ADDRESS 0x60080010
|
||||
|
||||
/*==============================================================================
|
||||
* MSS configuration location.
|
||||
*/
|
||||
#define MSS_CONFIG_ADDRESS 0x60081618
|
||||
|
||||
/*==============================================================================
|
||||
* Analog configuration location and size.
|
||||
*/
|
||||
#define ANALOG_CONFIG_ADDRESS 0x60081600
|
||||
#define ANALOG_CONFIG_BYTE_SIZE 24
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ENVM_LAYOUT_HEADER */
|
|
@ -0,0 +1,744 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SVN $Revision: 2905 $
|
||||
* SVN $Date: 2010-08-20 14:03:28 +0100 (Fri, 20 Aug 2010) $
|
||||
*/
|
||||
|
||||
#include "mss_ace.h"
|
||||
#include "mtd_data.h"
|
||||
#include "envm_layout.h"
|
||||
#include "mss_ace_configurator.h"
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
#include "../../drivers_config/mss_ace/ace_config.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define START_ADC_CONVERSION 0x80uL
|
||||
|
||||
|
||||
/**/
|
||||
void ace_init_flags( void );
|
||||
void ace_init_convert(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_init( void )
|
||||
{
|
||||
/* Initialize driver's internal data. */
|
||||
ace_init_flags();
|
||||
|
||||
/* Initialize the data structures used by conversion functions. */
|
||||
ace_init_convert();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_start_adc
|
||||
(
|
||||
adc_channel_id_t channel_id
|
||||
)
|
||||
{
|
||||
ACE->ADC0_CONV_CTRL = (uint32_t)channel_id | START_ADC_CONVERSION;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
#define ADC_DATAVALID_MASK 0x00001000uL
|
||||
#define ADC_RESULT_MASK 0x00000FFFuL
|
||||
|
||||
static const uint32_t volatile * const adc_status_reg_lut[NB_OF_ANALOG_MODULES] =
|
||||
{
|
||||
&ACE->ADC0_STATUS,
|
||||
&ACE->ADC1_STATUS,
|
||||
&ACE->ADC2_STATUS
|
||||
};
|
||||
|
||||
uint16_t ACE_get_adc_result
|
||||
(
|
||||
uint8_t adc_id
|
||||
)
|
||||
{
|
||||
uint16_t result = 0u;
|
||||
uint32_t data_valid;
|
||||
|
||||
ASSERT( adc_id < NB_OF_ANALOG_MODULES );
|
||||
|
||||
if ( adc_id < (uint8_t)NB_OF_ANALOG_MODULES )
|
||||
{
|
||||
do {
|
||||
data_valid = *adc_status_reg_lut[adc_id] & ADC_DATAVALID_MASK;
|
||||
} while ( !data_valid );
|
||||
|
||||
result = (uint16_t)(*adc_status_reg_lut[adc_id] & ADC_RESULT_MASK);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
=========== Sigma Delta Digital to Analog Converters (SDD) Control ============
|
||||
=============================================================================*/
|
||||
|
||||
#define SDD_ENABLE_MASK 0x20uL
|
||||
#define SDD_REG_SEL_MASK 0x40uL
|
||||
|
||||
#define DAC0_SYNC_EN_MASK 0x10uL
|
||||
#define DAC1_SYNC_EN_MASK 0x20uL
|
||||
#define DAC2_SYNC_EN_MASK 0x40uL
|
||||
|
||||
#define DAC0_SYNC_UPDATE 0x01uL
|
||||
#define DAC1_SYNC_UPDATE 0x02uL
|
||||
#define DAC2_SYNC_UPDATE 0x04uL
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
static volatile uint32_t * const dac_ctrl_reg_lut[NB_OF_ANALOG_MODULES] =
|
||||
{
|
||||
&ACE->DAC0_CTRL,
|
||||
&ACE->DAC1_CTRL,
|
||||
&ACE->DAC1_CTRL
|
||||
};
|
||||
|
||||
static const uint32_t dac_enable_masks_lut[NB_OF_ANALOG_MODULES] =
|
||||
{
|
||||
DAC0_SYNC_EN_MASK,
|
||||
DAC1_SYNC_EN_MASK,
|
||||
DAC2_SYNC_EN_MASK
|
||||
};
|
||||
|
||||
static volatile uint32_t * const dac_byte01_reg_lut[NB_OF_ANALOG_MODULES] =
|
||||
{
|
||||
&ACE->SSE_DAC0_BYTES01,
|
||||
&ACE->SSE_DAC1_BYTES01,
|
||||
&ACE->SSE_DAC2_BYTES01,
|
||||
};
|
||||
|
||||
static volatile uint32_t * const dac_byte2_reg_lut[NB_OF_ANALOG_MODULES] =
|
||||
{
|
||||
&ACE->DAC0_BYTE2,
|
||||
&ACE->DAC1_BYTE2,
|
||||
&ACE->DAC2_BYTE2
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Pointer to the manufacturing test data containing trimming information
|
||||
* generated during manufacturing.
|
||||
*/
|
||||
static const mtd_data_t * const p_mtd_data = (mtd_data_t *)MTD_ADDRESS;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
#define OBD_MODE_MASK (uint8_t)0x01
|
||||
#define OBD_CHOPPING_MASK (uint8_t)0x02
|
||||
|
||||
void ACE_configure_sdd
|
||||
(
|
||||
sdd_id_t sdd_id,
|
||||
sdd_resolution_t resolution,
|
||||
uint8_t mode,
|
||||
sdd_update_method_t sync_update
|
||||
)
|
||||
{
|
||||
ASSERT( sdd_id < NB_OF_SDD );
|
||||
|
||||
if ( sdd_id < NB_OF_SDD )
|
||||
{
|
||||
const uint8_t sdd_2_quad_lut[NB_OF_SDD] = {0u, 2u, 4u};
|
||||
uint8_t quad_id;
|
||||
uint8_t obd_mode_idx = 1u;
|
||||
uint8_t chopping_mode_idx = 0u;
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
quad_id = sdd_2_quad_lut[sdd_id];
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
/* Select between voltage/current and RTZ modes.*/
|
||||
ACE->ACB_DATA[quad_id].b6 = mode;
|
||||
|
||||
/* Load manufacturing generated trim value. */
|
||||
if ( (mode & OBD_MODE_MASK) > 0u )
|
||||
{
|
||||
obd_mode_idx = 0u;
|
||||
}
|
||||
if ( (mode & OBD_CHOPPING_MASK) > 0u )
|
||||
{
|
||||
chopping_mode_idx = 1u;
|
||||
}
|
||||
ACE->ACB_DATA[quad_id].b4
|
||||
= p_mtd_data->odb_trimming[sdd_id][obd_mode_idx][chopping_mode_idx];
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
|
||||
/* Set SDD resolution. */
|
||||
*dac_ctrl_reg_lut[sdd_id] = (uint32_t)resolution;
|
||||
|
||||
/* Update SDD value through SSE_DACn_BYTES01. */
|
||||
*dac_ctrl_reg_lut[sdd_id] |= SDD_REG_SEL_MASK;
|
||||
|
||||
/* Synchronous or individual SDD update. */
|
||||
if ( INDIVIDUAL_UPDATE == sync_update )
|
||||
{
|
||||
ACE->DAC_SYNC_CTRL &= ~dac_enable_masks_lut[sdd_id];
|
||||
}
|
||||
else
|
||||
{
|
||||
ACE->DAC_SYNC_CTRL |= dac_enable_masks_lut[sdd_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_enable_sdd
|
||||
(
|
||||
sdd_id_t sdd_id
|
||||
)
|
||||
{
|
||||
ASSERT( sdd_id < NB_OF_SDD );
|
||||
|
||||
if ( sdd_id < NB_OF_SDD )
|
||||
{
|
||||
*dac_ctrl_reg_lut[sdd_id] |= SDD_ENABLE_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_disable_sdd
|
||||
(
|
||||
sdd_id_t sdd_id
|
||||
)
|
||||
{
|
||||
ASSERT( sdd_id < NB_OF_SDD );
|
||||
|
||||
if ( sdd_id < NB_OF_SDD )
|
||||
{
|
||||
*dac_ctrl_reg_lut[sdd_id] &= ~SDD_ENABLE_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_set_sdd_value
|
||||
(
|
||||
sdd_id_t sdd_id,
|
||||
uint32_t sdd_value
|
||||
)
|
||||
{
|
||||
ASSERT( sdd_id < NB_OF_SDD );
|
||||
|
||||
if ( sdd_id < NB_OF_SDD )
|
||||
{
|
||||
*dac_byte2_reg_lut[sdd_id] = sdd_value >> 16;
|
||||
*dac_byte01_reg_lut[sdd_id] = sdd_value;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_set_sdd_value_sync
|
||||
(
|
||||
uint32_t sdd0_value,
|
||||
uint32_t sdd1_value,
|
||||
uint32_t sdd2_value
|
||||
)
|
||||
{
|
||||
uint32_t dac_sync_ctrl;
|
||||
|
||||
dac_sync_ctrl = ACE->DAC_SYNC_CTRL;
|
||||
|
||||
if ( SDD_NO_UPDATE != sdd0_value )
|
||||
{
|
||||
ACE->DAC0_BYTE2 = sdd0_value >> 16;
|
||||
ACE->SSE_DAC0_BYTES01 = sdd0_value;
|
||||
dac_sync_ctrl |= DAC0_SYNC_UPDATE;
|
||||
}
|
||||
|
||||
if ( SDD_NO_UPDATE != sdd1_value )
|
||||
{
|
||||
ACE->DAC1_BYTE2 = sdd1_value >> 16;
|
||||
ACE->SSE_DAC1_BYTES01 = sdd1_value;
|
||||
dac_sync_ctrl |= DAC1_SYNC_UPDATE;
|
||||
}
|
||||
|
||||
if ( SDD_NO_UPDATE != sdd2_value )
|
||||
{
|
||||
ACE->DAC2_BYTE2 = sdd2_value >> 16;
|
||||
ACE->DAC2_BYTE1 = sdd2_value >> 8;
|
||||
ACE->SSE_DAC2_BYTES01 = sdd2_value;
|
||||
dac_sync_ctrl |= DAC2_SYNC_UPDATE;
|
||||
}
|
||||
|
||||
ACE->DAC_SYNC_CTRL = dac_sync_ctrl;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
============================ Comparators Control ==============================
|
||||
=============================================================================*/
|
||||
|
||||
/*
|
||||
* SDD Analog switch mask. ACB byte 10.
|
||||
* 0: TMB comparator reference voltage is an ADC direct input
|
||||
* 1: TMB comparator reference voltage is one of the SDD outputs as
|
||||
* selected by DAC_MUXSEL[1:0]
|
||||
*/
|
||||
#define B10_COMP_VREF_SW_MASK 0x20u
|
||||
|
||||
/*
|
||||
* Comparator reference voltage multiplexer.
|
||||
* Used to select which SDD output will be used as reference voltage for TMB
|
||||
* comparator. These bits are only meaningful when COMP_VREF_SW is set to 1.
|
||||
*/
|
||||
#define B11_DAC_MUXSEL_MASK 0x03u
|
||||
|
||||
/*
|
||||
* Number of bits to shift a value of type comp_hysteresis_t to get the
|
||||
* hysteresis to program into ACB b9 or b10.
|
||||
*/
|
||||
#define HYSTERESIS_SHIFT 6u
|
||||
|
||||
/*
|
||||
* Mask of hysteresis bits within ACB b9 or b10.
|
||||
*/
|
||||
#define HYSTERESIS_MASK 0xC0u
|
||||
|
||||
/*
|
||||
* Mask of the comparator enable bit within ACB b9 and b10.
|
||||
*/
|
||||
#define COMPARATOR_ENABLE_MASK 0x10u
|
||||
|
||||
/*
|
||||
* Comparator ID to Signal Conditioning Block (SCB) lookup table.
|
||||
* USe to find which SCB a comparator belongs to.
|
||||
*/
|
||||
const uint8_t comp_id_2_scb_lut[NB_OF_COMPARATORS] =
|
||||
{
|
||||
0u, /* CMP0 */
|
||||
0u, /* CMP1 */
|
||||
1u, /* CMP2 */
|
||||
1u, /* CMP3 */
|
||||
2u, /* CMP4 */
|
||||
2u, /* CMP5 */
|
||||
3u, /* CMP6 */
|
||||
3u, /* CMP7 */
|
||||
4u, /* CMP8 */
|
||||
4u, /* CMP9 */
|
||||
5u, /* CMP10 */
|
||||
5u /* CMP11 */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* This function is requred to configure comparators included in temperature
|
||||
* monitor blocks.
|
||||
*/
|
||||
void ACE_set_comp_reference
|
||||
(
|
||||
comparator_id_t comp_id,
|
||||
comp_reference_t reference
|
||||
)
|
||||
{
|
||||
uint8_t scb_id;
|
||||
uint32_t odd;
|
||||
|
||||
odd = (uint32_t)comp_id & 0x01uL;
|
||||
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
ASSERT( reference < NB_OF_COMP_REF );
|
||||
ASSERT( odd ); /* Only Temperature block comparators have configurable reference input. */
|
||||
|
||||
if ( (comp_id < NB_OF_COMPARATORS) && (reference < NB_OF_COMP_REF) && (odd) )
|
||||
{
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
scb_id = comp_id_2_scb_lut[comp_id];
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
if ( ADC_IN_COMP_REF == reference )
|
||||
{
|
||||
ACE->ACB_DATA[scb_id].b10 &= (uint8_t)~B10_COMP_VREF_SW_MASK;
|
||||
ACE->ACB_DATA[scb_id].b11 &= (uint8_t)~B11_DAC_MUXSEL_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ACE->ACB_DATA[scb_id].b10 &= (uint8_t)~B10_COMP_VREF_SW_MASK;
|
||||
ACE->ACB_DATA[scb_id].b11 = (ACE->ACB_DATA[scb_id].b11 & (uint8_t)~B11_DAC_MUXSEL_MASK) + (uint8_t)reference;
|
||||
}
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* Set analog block comparators hysteresis.
|
||||
*/
|
||||
void ACE_set_comp_hysteresis
|
||||
(
|
||||
comparator_id_t comp_id,
|
||||
comp_hysteresis_t hysteresis
|
||||
)
|
||||
{
|
||||
uint8_t scb_id;
|
||||
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
ASSERT( hysteresis < NB_OF_HYSTERESIS );
|
||||
|
||||
if ( (comp_id < NB_OF_COMPARATORS) && (hysteresis < NB_OF_HYSTERESIS) )
|
||||
{
|
||||
uint32_t odd;
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
scb_id = comp_id_2_scb_lut[comp_id];
|
||||
odd = (uint32_t)comp_id & 0x01uL;
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
if ( odd )
|
||||
{
|
||||
/* Temperature monitor block comparator. */
|
||||
ACE->ACB_DATA[scb_id].b10 = (ACE->ACB_DATA[scb_id].b10 & HYSTERESIS_MASK) | (uint8_t)((uint8_t)hysteresis << HYSTERESIS_SHIFT);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Current monitor block comparator. */
|
||||
ACE->ACB_DATA[scb_id].b9 = (ACE->ACB_DATA[scb_id].b9 & HYSTERESIS_MASK) | (uint8_t)((uint8_t)hysteresis << HYSTERESIS_SHIFT);
|
||||
}
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
|
||||
*/
|
||||
void ACE_enable_comp
|
||||
(
|
||||
comparator_id_t comp_id
|
||||
)
|
||||
{
|
||||
uint8_t scb_id;
|
||||
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
if ( comp_id < NB_OF_COMPARATORS )
|
||||
{
|
||||
uint32_t odd;
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
scb_id = comp_id_2_scb_lut[comp_id];
|
||||
odd = (uint32_t)comp_id & 0x01uL;
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
if ( odd )
|
||||
{
|
||||
/* Temperature monitor block comparator. */
|
||||
ACE->ACB_DATA[scb_id].b10 |= COMPARATOR_ENABLE_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Current monitor block comparator. */
|
||||
ACE->ACB_DATA[scb_id].b9 |= COMPARATOR_ENABLE_MASK;
|
||||
}
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
void ACE_disable_comp
|
||||
(
|
||||
comparator_id_t comp_id
|
||||
)
|
||||
{
|
||||
uint8_t scb_id;
|
||||
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
if ( comp_id < NB_OF_COMPARATORS )
|
||||
{
|
||||
uint32_t odd;
|
||||
uint32_t saved_pc2_ctrl;
|
||||
|
||||
scb_id = comp_id_2_scb_lut[comp_id];
|
||||
odd = (uint32_t)comp_id & 0x01uL;
|
||||
|
||||
/* Pause the SSE PC2 while accesses to ACB from APB3 are taking place. */
|
||||
saved_pc2_ctrl = ACE->PC2_CTRL;
|
||||
ACE->PC2_CTRL = 0u;
|
||||
|
||||
if ( odd )
|
||||
{
|
||||
/* Temperature monitor block comparator. */
|
||||
ACE->ACB_DATA[scb_id].b10 &= (uint8_t)~COMPARATOR_ENABLE_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Current monitor block comparator. */
|
||||
ACE->ACB_DATA[scb_id].b9 &= (uint8_t)~COMPARATOR_ENABLE_MASK;
|
||||
}
|
||||
|
||||
/* Restore SSE PC2 operations since no ACB accesses should take place
|
||||
* beyond this point. */
|
||||
ACE->PC2_CTRL = saved_pc2_ctrl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Bit mask of comparator 0 rise interrupt bit.
|
||||
* Shift this value left by the value of the comparator ID to obtain the bit
|
||||
* mask used enable/disable/clear rise interrupts from that comparator.
|
||||
*/
|
||||
#define FIRST_RISE_IRQ_MASK 0x00000800uL
|
||||
|
||||
/*
|
||||
* Bit mask of comparator 0 fall interrupt bit.
|
||||
* Shift this value left by the value of the comparator ID to obtain the bit
|
||||
* mask used enable/disable/clear fall interrupts from that comparator.
|
||||
*/
|
||||
#define FIRST_FALL_IRQ_MASK 0x00000001uL
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_enable_comp_rise_irq
|
||||
(
|
||||
comparator_id_t comp_id
|
||||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
ACE->COMP_IRQ_EN |= (FIRST_RISE_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_disable_comp_rise_irq
|
||||
(
|
||||
comparator_id_t comp_id
|
||||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
ACE->COMP_IRQ_EN &= ~(FIRST_RISE_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_clear_comp_rise_irq
|
||||
(
|
||||
comparator_id_t comp_id
|
||||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
ACE->COMP_IRQ_CLR |= (FIRST_RISE_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_enable_comp_fall_irq
|
||||
(
|
||||
comparator_id_t comp_id
|
||||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
ACE->COMP_IRQ_EN |= (FIRST_FALL_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_disable_comp_fall_irq
|
||||
(
|
||||
comparator_id_t comp_id
|
||||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
ACE->COMP_IRQ_EN &= ~(FIRST_FALL_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
void ACE_clear_comp_fall_irq
|
||||
(
|
||||
comparator_id_t comp_id
|
||||
)
|
||||
{
|
||||
ASSERT( comp_id < NB_OF_COMPARATORS );
|
||||
|
||||
ACE->COMP_IRQ_CLR |= (FIRST_FALL_IRQ_MASK << (uint32_t)comp_id);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* Returns the raw analog quad comparator status.
|
||||
*/
|
||||
uint32_t ACE_get_comp_status( void )
|
||||
{
|
||||
return ACE->COMP_IRQ;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
============ Reading Samples from post processing engine (PPE) ================
|
||||
=============================================================================*/
|
||||
extern ace_channel_desc_t g_ace_channel_desc_table[ACE_NB_OF_INPUT_CHANNELS];
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
uint32_t
|
||||
ACE_get_channel_count
|
||||
(
|
||||
void
|
||||
)
|
||||
{
|
||||
return (uint32_t)ACE_NB_OF_INPUT_CHANNELS;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
ace_channel_handle_t
|
||||
ACE_get_first_channel
|
||||
(
|
||||
void
|
||||
)
|
||||
{
|
||||
ace_channel_handle_t channel_handle;
|
||||
|
||||
channel_handle = (ace_channel_handle_t)0;
|
||||
|
||||
return channel_handle;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
ace_channel_handle_t
|
||||
ACE_get_next_channel
|
||||
(
|
||||
ace_channel_handle_t channel_handle
|
||||
)
|
||||
{
|
||||
++channel_handle;
|
||||
|
||||
if ( channel_handle >= NB_OF_ACE_CHANNEL_HANDLES )
|
||||
{
|
||||
channel_handle = (ace_channel_handle_t)0;
|
||||
}
|
||||
|
||||
return channel_handle;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
ace_channel_handle_t
|
||||
ACE_get_channel_handle
|
||||
(
|
||||
const uint8_t * p_sz_channel_name
|
||||
)
|
||||
{
|
||||
uint16_t channel_idx;
|
||||
ace_channel_handle_t channel_handle = INVALID_CHANNEL_HANDLE;
|
||||
|
||||
for ( channel_idx = 0u; channel_idx < (uint16_t)ACE_NB_OF_INPUT_CHANNELS; ++channel_idx )
|
||||
{
|
||||
if ( g_ace_channel_desc_table[channel_idx].p_sz_channel_name != 0 )
|
||||
{
|
||||
int32_t diff;
|
||||
diff = strncmp( (const char*)p_sz_channel_name, (const char*)g_ace_channel_desc_table[channel_idx].p_sz_channel_name, MAX_CHANNEL_NAME_LENGTH );
|
||||
if ( 0 == diff )
|
||||
{
|
||||
/* channel name found. */
|
||||
channel_handle = (ace_channel_handle_t)channel_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return channel_handle;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
ace_channel_handle_t
|
||||
ACE_get_input_channel_handle
|
||||
(
|
||||
adc_channel_id_t channel_id
|
||||
)
|
||||
{
|
||||
uint16_t channel_idx;
|
||||
ace_channel_handle_t channel_handle = INVALID_CHANNEL_HANDLE;
|
||||
|
||||
for ( channel_idx = 0u; channel_idx < (uint16_t)ACE_NB_OF_INPUT_CHANNELS; ++channel_idx )
|
||||
{
|
||||
if ( g_ace_channel_desc_table[channel_idx].signal_id == channel_id )
|
||||
{
|
||||
/* channel ID found. */
|
||||
channel_handle = (ace_channel_handle_t)channel_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return channel_handle;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
See "mss_ace.h" for details of how to use this function.
|
||||
*/
|
||||
uint16_t
|
||||
ACE_get_ppe_sample
|
||||
(
|
||||
ace_channel_handle_t channel_handle
|
||||
)
|
||||
{
|
||||
uint16_t sample;
|
||||
uint16_t ppe_offset;
|
||||
|
||||
ppe_offset = g_ace_channel_desc_table[channel_handle].signal_ppe_offset;
|
||||
sample = (uint16_t)(ACE->PPE_RAM_DATA[ppe_offset] >> 16u);
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,622 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SVN $Revision: 2841 $
|
||||
* SVN $Date: 2010-07-20 18:10:00 +0100 (Tue, 20 Jul 2010) $
|
||||
*/
|
||||
|
||||
/*=========================================================================*//**
|
||||
@mainpage ACE Configurator data provided to ACE Driver.
|
||||
|
||||
@section intro_sec Introduction
|
||||
This file contains the definition of data structures used by the ACE
|
||||
Configurator software tool for sharing information about the ACE configuration
|
||||
with the ACE driver. It also contains the API for accessor functions used by
|
||||
the ACE driver to extract relevant information from these data structures.
|
||||
*//*=========================================================================*/
|
||||
#ifndef __MSS_ACE_CONFIGURATOR_H_
|
||||
#define __MSS_ACE_CONFIGURATOR_H_
|
||||
|
||||
#include "mss_ace.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Post Processing Engine (PPE) flags IDs.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
PPE_FLAGS0_0 = 0,
|
||||
PPE_FLAGS0_1 = 1,
|
||||
PPE_FLAGS0_2 = 2,
|
||||
PPE_FLAGS0_3 = 3,
|
||||
PPE_FLAGS0_4 = 4,
|
||||
PPE_FLAGS0_5 = 5,
|
||||
PPE_FLAGS0_6 = 6,
|
||||
PPE_FLAGS0_7 = 7,
|
||||
PPE_FLAGS0_8 = 8,
|
||||
PPE_FLAGS0_9 = 9,
|
||||
PPE_FLAGS0_10 = 10,
|
||||
PPE_FLAGS0_11 = 11,
|
||||
PPE_FLAGS0_12 = 12,
|
||||
PPE_FLAGS0_13 = 13,
|
||||
PPE_FLAGS0_14 = 14,
|
||||
PPE_FLAGS0_15 = 15,
|
||||
PPE_FLAGS0_16 = 16,
|
||||
PPE_FLAGS0_17 = 17,
|
||||
PPE_FLAGS0_18 = 18,
|
||||
PPE_FLAGS0_19 = 19,
|
||||
PPE_FLAGS0_20 = 20,
|
||||
PPE_FLAGS0_21 = 21,
|
||||
PPE_FLAGS0_22 = 22,
|
||||
PPE_FLAGS0_23 = 23,
|
||||
PPE_FLAGS0_24 = 24,
|
||||
PPE_FLAGS0_25 = 25,
|
||||
PPE_FLAGS0_26 = 26,
|
||||
PPE_FLAGS0_27 = 27,
|
||||
PPE_FLAGS0_28 = 28,
|
||||
PPE_FLAGS0_29 = 29,
|
||||
PPE_FLAGS0_30 = 30,
|
||||
PPE_FLAGS0_31 = 31,
|
||||
PPE_FLAGS1_0 = 32,
|
||||
PPE_FLAGS1_1 = 33,
|
||||
PPE_FLAGS1_2 = 34,
|
||||
PPE_FLAGS1_3 = 35,
|
||||
PPE_FLAGS1_4 = 36,
|
||||
PPE_FLAGS1_5 = 37,
|
||||
PPE_FLAGS1_6 = 38,
|
||||
PPE_FLAGS1_7 = 39,
|
||||
PPE_FLAGS1_8 = 40,
|
||||
PPE_FLAGS1_9 = 41,
|
||||
PPE_FLAGS1_10 = 42,
|
||||
PPE_FLAGS1_11 = 43,
|
||||
PPE_FLAGS1_12 = 44,
|
||||
PPE_FLAGS1_13 = 45,
|
||||
PPE_FLAGS1_14 = 46,
|
||||
PPE_FLAGS1_15 = 47,
|
||||
PPE_FLAGS1_16 = 48,
|
||||
PPE_FLAGS1_17 = 49,
|
||||
PPE_FLAGS1_18 = 50,
|
||||
PPE_FLAGS1_19 = 51,
|
||||
PPE_FLAGS1_20 = 52,
|
||||
PPE_FLAGS1_21 = 53,
|
||||
PPE_FLAGS1_22 = 54,
|
||||
PPE_FLAGS1_23 = 55,
|
||||
PPE_FLAGS1_24 = 56,
|
||||
PPE_FLAGS1_25 = 57,
|
||||
PPE_FLAGS1_26 = 58,
|
||||
PPE_FLAGS1_27 = 59,
|
||||
PPE_FLAGS1_28 = 60,
|
||||
PPE_FLAGS1_29 = 61,
|
||||
PPE_FLAGS1_30 = 62,
|
||||
PPE_FLAGS1_31 = 63,
|
||||
PPE_FLAGS2_0 = 64,
|
||||
PPE_FLAGS2_1 = 65,
|
||||
PPE_FLAGS2_2 = 66,
|
||||
PPE_FLAGS2_3 = 67,
|
||||
PPE_FLAGS2_4 = 68,
|
||||
PPE_FLAGS2_5 = 69,
|
||||
PPE_FLAGS2_6 = 70,
|
||||
PPE_FLAGS2_7 = 71,
|
||||
PPE_FLAGS2_8 = 72,
|
||||
PPE_FLAGS2_9 = 73,
|
||||
PPE_FLAGS2_10 = 74,
|
||||
PPE_FLAGS2_11 = 75,
|
||||
PPE_FLAGS2_12 = 76,
|
||||
PPE_FLAGS2_13 = 77,
|
||||
PPE_FLAGS2_14 = 78,
|
||||
PPE_FLAGS2_15 = 79,
|
||||
PPE_FLAGS2_16 = 80,
|
||||
PPE_FLAGS2_17 = 81,
|
||||
PPE_FLAGS2_18 = 82,
|
||||
PPE_FLAGS2_19 = 83,
|
||||
PPE_FLAGS2_20 = 84,
|
||||
PPE_FLAGS2_21 = 85,
|
||||
PPE_FLAGS2_22 = 86,
|
||||
PPE_FLAGS2_23 = 87,
|
||||
PPE_FLAGS2_24 = 88,
|
||||
PPE_FLAGS2_25 = 89,
|
||||
PPE_FLAGS2_26 = 90,
|
||||
PPE_FLAGS2_27 = 91,
|
||||
PPE_FLAGS2_28 = 92,
|
||||
PPE_FLAGS2_29 = 93,
|
||||
PPE_FLAGS2_30 = 94,
|
||||
PPE_FLAGS2_31 = 95,
|
||||
PPE_FLAGS3_0 = 96,
|
||||
PPE_FLAGS3_1 = 97,
|
||||
PPE_FLAGS3_2 = 98,
|
||||
PPE_FLAGS3_3 = 99,
|
||||
PPE_FLAGS3_4 = 100,
|
||||
PPE_FLAGS3_5 = 101,
|
||||
PPE_FLAGS3_6 = 102,
|
||||
PPE_FLAGS3_7 = 103,
|
||||
PPE_FLAGS3_8 = 104,
|
||||
PPE_FLAGS3_9 = 105,
|
||||
PPE_FLAGS3_10 = 106,
|
||||
PPE_FLAGS3_11 = 107,
|
||||
PPE_FLAGS3_12 = 108,
|
||||
PPE_FLAGS3_13 = 109,
|
||||
PPE_FLAGS3_14 = 110,
|
||||
PPE_FLAGS3_15 = 111,
|
||||
PPE_FLAGS3_16 = 112,
|
||||
PPE_FLAGS3_17 = 113,
|
||||
PPE_FLAGS3_18 = 114,
|
||||
PPE_FLAGS3_19 = 115,
|
||||
PPE_FLAGS3_20 = 116,
|
||||
PPE_FLAGS3_21 = 117,
|
||||
PPE_FLAGS3_22 = 118,
|
||||
PPE_FLAGS3_23 = 119,
|
||||
PPE_FLAGS3_24 = 120,
|
||||
PPE_FLAGS3_25 = 121,
|
||||
PPE_FLAGS3_26 = 122,
|
||||
PPE_FLAGS3_27 = 123,
|
||||
PPE_FLAGS3_28 = 124,
|
||||
PPE_FLAGS3_29 = 125,
|
||||
PPE_FLAGS3_30 = 126,
|
||||
PPE_FLAGS3_31 = 127,
|
||||
PPE_SFFLAGS_0 = 128,
|
||||
PPE_SFFLAGS_1 = 129,
|
||||
PPE_SFFLAGS_2 = 130,
|
||||
PPE_SFFLAGS_3 = 131,
|
||||
PPE_SFFLAGS_4 = 132,
|
||||
PPE_SFFLAGS_5 = 133,
|
||||
PPE_SFFLAGS_6 = 134,
|
||||
PPE_SFFLAGS_7 = 135,
|
||||
PPE_SFFLAGS_8 = 136,
|
||||
PPE_SFFLAGS_9 = 137,
|
||||
PPE_SFFLAGS_10 = 138,
|
||||
PPE_SFFLAGS_11 = 139,
|
||||
PPE_SFFLAGS_12 = 140,
|
||||
PPE_SFFLAGS_13 = 141,
|
||||
PPE_SFFLAGS_14 = 142,
|
||||
PPE_SFFLAGS_15 = 143,
|
||||
PPE_SFFLAGS_16 = 144,
|
||||
PPE_SFFLAGS_17 = 145,
|
||||
PPE_SFFLAGS_18 = 146,
|
||||
PPE_SFFLAGS_19 = 147,
|
||||
PPE_SFFLAGS_20 = 148,
|
||||
PPE_SFFLAGS_21 = 149,
|
||||
PPE_SFFLAGS_22 = 150,
|
||||
PPE_SFFLAGS_23 = 151,
|
||||
PPE_SFFLAGS_24 = 152,
|
||||
PPE_SFFLAGS_25 = 153,
|
||||
PPE_SFFLAGS_26 = 154,
|
||||
PPE_SFFLAGS_27 = 155,
|
||||
PPE_SFFLAGS_28 = 156,
|
||||
PPE_SFFLAGS_29 = 157,
|
||||
PPE_SFFLAGS_30 = 158,
|
||||
PPE_SFFLAGS_31 = 159,
|
||||
NB_OF_PPE_FLAGS = 160
|
||||
} ppe_flag_id_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Flag types.
|
||||
The following defines are used to indicate the type of flag selected in the
|
||||
ACE configurator.
|
||||
*/
|
||||
/**
|
||||
A flag configured as BASIC_THRESHOLD_OVER will be asserted when the value of
|
||||
the input channel exceeds the value of the flag threshold. The flag will be
|
||||
de-asserted once the value of the input channel falls back under the threshold
|
||||
value. No hysteresis or state filtering is applied to the flag.
|
||||
*/
|
||||
#define BASIC_THRESHOLD_OVER 0u
|
||||
|
||||
/**
|
||||
A flag configured as BASIC_THRESHOLD_UNDER will be asserted when the value of
|
||||
the input channel falls under the value of the flag threshold. The flag will be
|
||||
de-asserted once the value of the input channel exceeds the threshold value.
|
||||
No hysteresis or state filtering is applied to the flag.
|
||||
*/
|
||||
#define BASIC_THRESHOLD_UNDER 1u
|
||||
|
||||
/**
|
||||
A flag configured as STATE_FILTERED_OVER will be asserted when n consecutive
|
||||
samples of the analog input are seen to exceed the value of the flag threshold,
|
||||
where n is the number selected in the "assert samples" option of the ACE
|
||||
configuration softwaretool flag's configuration.
|
||||
The flag will be de-asserted once m consecutive samples as seen below the flag
|
||||
threshold value, where m is the number selected in the "deassert samples"
|
||||
option of the flag's configuration user interface.
|
||||
*/
|
||||
#define STATE_FILTERED_OVER 2u
|
||||
|
||||
/**
|
||||
A flag configured as STATE_FILTERED_UNDER will be asserted when n consecutive
|
||||
samples of the analog input are seen below the value of the flag threshold,
|
||||
where n is the number selected in the "assert samples" option of the ACE
|
||||
configuration softwaretool flag's configuration.
|
||||
The flag will be de-asserted once m consecutive samples as seen to exceed the
|
||||
flag threshold value, where m is the number selected in the "deassert samples"
|
||||
option of the flag's configuration user interface.
|
||||
*/
|
||||
#define STATE_FILTERED_UNDER 3u
|
||||
|
||||
/**
|
||||
A flag configured as DUAL_HYSTERESIS_OVER will be asserted when the value
|
||||
of the input channel exceeds the threshold value plus the hysteresis value.
|
||||
The flag will be deasserted when the value of the input channel falls under the
|
||||
threshold value minus the hysteresis value.
|
||||
*/
|
||||
#define DUAL_HYSTERESIS_OVER 4u
|
||||
|
||||
/**
|
||||
A flag configured as DUAL_HYSTERESIS_UNDER will be asserted when the value
|
||||
of the input channel falls under the threshold value minus the hysteresis value.
|
||||
The flag will be deasserted when the value of the input channel exceeds the
|
||||
threshold value plus the hysteresis value.
|
||||
*/
|
||||
#define DUAL_HYSTERESIS_UNDER 5u
|
||||
|
||||
/**
|
||||
A flag configured as IPMI_HYSTERESIS_OVER will be asserted when the value
|
||||
of the input channel exceeds the threshold value. The flag will be deasserted
|
||||
when the value of the input channel falls under the threshold value minus the
|
||||
hysteresis value.
|
||||
*/
|
||||
#define IPMI_HYSTERESIS_OVER 6u
|
||||
|
||||
/**
|
||||
A flag configured as IPMI_HYSTERESIS_UNDER will be asserted when the value
|
||||
of the input channel falls under the threshold value. The flag will be
|
||||
deasserted when the value of the input channel exceeds the threshold value
|
||||
plus the hysteresis value.
|
||||
*/
|
||||
#define IPMI_HYSTERESIS_UNDER 7u
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
State filtered flag configuration.
|
||||
*/
|
||||
typedef struct __state_filtering_cfg
|
||||
{
|
||||
/**
|
||||
Number of consecutive samples required for flag assertion.
|
||||
*/
|
||||
uint8_t assert_samples;
|
||||
|
||||
/**
|
||||
Number of consecutive samples required for flag deassertion.
|
||||
*/
|
||||
uint8_t deassert_samples;
|
||||
} state_filtering_cfg_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
Post Processing Engine generated flag descriptor.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
Pointer to a zero-terminated string identifying the flag described by this
|
||||
structure. This unique flag name is the name selected in the ACE configurator
|
||||
software tool when creating a flag.
|
||||
The flag unique name contains both the name of the monitored input channel
|
||||
and the name of the flag generated based the level of that input separated
|
||||
by ":". For example, the unique name for the flag called "CriticalOver"
|
||||
raised when the input channel called "MainSupply" reaches a critical level
|
||||
would be named "MainSupply:CriticalOver".
|
||||
*/
|
||||
const uint8_t * p_sz_flag_name;
|
||||
|
||||
/**
|
||||
The flag_id element identifies which PPE hardware flag will be asserted
|
||||
when the flag conditions are found to be met by the Post Processing Engine.
|
||||
This flag_id is typically used by the ACE driver to determine which ACE
|
||||
register is used to enable, disable and clear interrupts on the associated
|
||||
flag.
|
||||
*/
|
||||
ppe_flag_id_t flag_id;
|
||||
|
||||
/**
|
||||
The flag_type element specifies the type of the described flag. It is
|
||||
specified using one of the following:
|
||||
- BASIC_THRESHOLD_OVER
|
||||
- BASIC_THRESHOLD_UNDER
|
||||
- STATE_FILTERED_OVER
|
||||
- STATE_FILTERED_UNDER
|
||||
- DUAL_HYSTERESIS_OVER
|
||||
- DUAL_HYSTERESIS_UNDER
|
||||
- IPMI_HYSTERESIS_OVER
|
||||
- IPMI_HYSTERESIS_UNDER
|
||||
*/
|
||||
uint8_t flag_type;
|
||||
|
||||
/**
|
||||
PPE RAM offset of flag threshold level.
|
||||
This is the 32-bit word offset within the Post Processing Engine RAM where
|
||||
the threshold associated with this flag is stored. This is used to allow
|
||||
the ACE driver dynamically modifying the threshold beyond which a flag is
|
||||
asserted.
|
||||
In the case of hysteresis flags, threshold_ppe_offset indicates the
|
||||
start location of two consecutive PPE RAM words containing the ADC value
|
||||
of the hysteresis low limit followed by the ADC value for the high
|
||||
hysteresis limit.
|
||||
*/
|
||||
uint16_t threshold_ppe_offset;
|
||||
|
||||
/**
|
||||
The default_threshold element specifies the value of the flag's threshold
|
||||
selected in the ACE Configurator. It is the ADC value for which the flag
|
||||
would be raised if hysteresis was not applied.
|
||||
*/
|
||||
uint16_t default_threshold;
|
||||
|
||||
/**
|
||||
The flag_properties takes a different meaning depending whether the flag is
|
||||
an hysteresis flag or a state filtered flag.
|
||||
|
||||
Hysteresis flags:
|
||||
The flag_properties element specifies the ADC value to be applied as
|
||||
hysteresis to the threshold value that was selected in the ACE Configurator.
|
||||
A non-zero value indicates that an hysteresis must be applied and that
|
||||
threshold_ppe_offset refers to the first of the two ADC values defining
|
||||
the hysteresis applied to the input signal.
|
||||
|
||||
State filtered flags:
|
||||
The flag_properties element specifies the number of consecutive samples that
|
||||
must be over or under the threshold value for the flag state to change.
|
||||
*/
|
||||
uint16_t flag_properties;
|
||||
|
||||
/**
|
||||
The channel_handle element specifies the monitored analog input channel.
|
||||
It can be used as parameter to a call to function ACE_get_ppe_sample() in
|
||||
order to read the current value of the analog input channel which caused
|
||||
the flag described by this structure to be raised.
|
||||
*/
|
||||
ace_channel_handle_t channel_handle;
|
||||
|
||||
} ppe_flag_desc_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The ace_procedure_desc_t structure is used as a procedure descriptor. It
|
||||
contains all information required by the ACE driver to use and manage an ACE
|
||||
procedure that was created using the ACE Configurator software tool.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
Pointer to a zero-terminated string identifying an ACE procedure.
|
||||
This procedure name is the one selected when created procedures using the
|
||||
ACE Configurator software tool.
|
||||
*/
|
||||
const uint8_t * p_sz_proc_name;
|
||||
|
||||
/**
|
||||
Sample Sequencing Engine procedure loop start program counter value.
|
||||
*/
|
||||
uint16_t sse_loop_pc;
|
||||
|
||||
/**
|
||||
Sample Sequencing Engine microcode offset.
|
||||
This is the 16-bit instruction offset from which the SSE microcode for the
|
||||
procedure must be loaded at into the ACE SSE RAM.
|
||||
This is also the value that must be writtent into one of the ACE's SSE program
|
||||
counter registers in order to start the procedure after having loaded its
|
||||
microcode into SSE RAM. The actual program counter register written depends
|
||||
on the analog module used by the procedure. It is determined by the value
|
||||
of this structure's sse_pc_id element.
|
||||
*/
|
||||
uint16_t sse_load_offset;
|
||||
|
||||
/**
|
||||
Sample Sequencing Engine microcode length.
|
||||
This is the number of 16-bit SSE instructions that must be loaded into
|
||||
SSE RAM in order to load the procedure into the ACE.
|
||||
*/
|
||||
uint16_t sse_ucode_length;
|
||||
|
||||
/**
|
||||
Pointer to ucode.
|
||||
*/
|
||||
const uint16_t * sse_ucode;
|
||||
|
||||
/**
|
||||
SSE program counter ID.
|
||||
This value identifies whether the procedure is used to control analog
|
||||
module 0, 1 or 2. It is used to know which SSE program counter should
|
||||
be set when starting the procedure.
|
||||
*/
|
||||
uint8_t sse_pc_id;
|
||||
} ace_procedure_desc_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The ace_channel_desc_t structure is used as an analog input channel
|
||||
descriptor. It contains the name of a channel as selected in the ACE
|
||||
Configurator software tool and the identifier used to identify the ADC channel
|
||||
to which the analog input signal is connected.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
Analog input signal name as selected in the ACE Configurator software tool.
|
||||
*/
|
||||
const uint8_t * p_sz_channel_name;
|
||||
|
||||
/**
|
||||
Analog block input channel connected to the input signal.
|
||||
*/
|
||||
adc_channel_id_t signal_id;
|
||||
|
||||
/**
|
||||
Offset into Post Processing Engine RAM where the result of post processing
|
||||
on sample for the signal will be stored.
|
||||
*/
|
||||
uint16_t signal_ppe_offset;
|
||||
|
||||
/**
|
||||
Number of PPE generated flags associated with the analog input channel
|
||||
described by this structure. The nb_of_flags specifies the number of items
|
||||
found in the p_flags_array array.
|
||||
*/
|
||||
uint16_t nb_of_flags;
|
||||
|
||||
/**
|
||||
The p_flags_array element is a pointer to an array of indexes into the
|
||||
g_ppe_flags_desc_table flag descriptors table. The array it points to
|
||||
lists the flags generated base don the value of the analog input channel
|
||||
described by this structure.
|
||||
*/
|
||||
const uint16_t * p_flags_array;
|
||||
|
||||
} ace_channel_desc_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
struct ace_config_desc_t
|
||||
The ace_config_descr_t structure is used to provide information about the
|
||||
configuration of the ACE and analog block. A single instance of this structure
|
||||
is intended to be used to inform the ACE driver of the ACE configuration
|
||||
seleted using the ACE Configurator software tool and programmed into the ACE
|
||||
hardware at system boot time.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/*--------------------------------------------------------------------------
|
||||
* Procedures information
|
||||
*/
|
||||
/**
|
||||
Procedure descriptors table location.
|
||||
This is a pointer to an array of procedure descriptors.
|
||||
@see nb_of_procedures
|
||||
*/
|
||||
ace_procedure_desc_t * proc_descr_table;
|
||||
|
||||
/**
|
||||
Total number of available procedures. This indicates the number of elements
|
||||
of the procedure descriptor array.
|
||||
@see proc_descr_table
|
||||
*/
|
||||
uint16_t nb_of_procedures;
|
||||
|
||||
/**
|
||||
Number of procedures loaded into the ACE hardware at system boot time.
|
||||
@see boot_loaded_proc_idx_list
|
||||
*/
|
||||
uint16_t nb_boot_loaded_proc;
|
||||
/**
|
||||
Pointer to list of procedures loaded into the ACE hardware at system boot
|
||||
time. That list contains the indexes into the procedure descriptors array
|
||||
of the procedures loaded into the ACE hardware.
|
||||
@see nb_boot_loaded_proc
|
||||
*/
|
||||
uint16_t * boot_loaded_proc_idx_list;
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
* Analog to Digital Converter signals
|
||||
*/
|
||||
/**
|
||||
Total number of configured analog input signals.
|
||||
This is the number of analog input signals that were added to the ACE
|
||||
configuration using the ACE Configurator software tool. It is also the
|
||||
number of elements in the signal descriptor table pointed to by this
|
||||
structure's signals_descr_table field.
|
||||
@see signals_descr_table
|
||||
*/
|
||||
uint16_t nb_of_signals;
|
||||
|
||||
/**
|
||||
Signal descriptors table location.
|
||||
This is a pointer to an array of signal descriptors describing every
|
||||
configured analog input signals.
|
||||
@see nb_of_signals
|
||||
*/
|
||||
ace_channel_desc_t * signals_descr_table;
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
* One Bit DACs
|
||||
*/
|
||||
/**
|
||||
One Bit DAC (OBD) names as specified in ACE configurator software tool.
|
||||
This array is indexed on the analog block number. i.e. sz_obd_names[0]
|
||||
contains the name used to identify the OBD contained in analog module 0.
|
||||
A value of 0 in this array indicates that no name was assigned to the
|
||||
associated OBD.
|
||||
*/
|
||||
const uint8_t * sz_obd_names[3];
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
* PPE generated flags
|
||||
*/
|
||||
/**
|
||||
Flag descriptors array location.
|
||||
This is a pointer to an array of ppe_flag_desc_t structures describing the
|
||||
properties of each of the flags generated by the Post Processing Engine.
|
||||
The size of that array is specified by the nb_of_flags element of this
|
||||
structure.
|
||||
*/
|
||||
ppe_flag_desc_t * flags_descr_table;
|
||||
|
||||
/**
|
||||
Number of flags used in the ACE Configurator generated configuration.
|
||||
*/
|
||||
uint8_t nb_of_flags;
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
* Analog comparators
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
} ace_config_desc_t;
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The ace_adc_config_t data structure is used by the ACE configurator to inform
|
||||
the ACE driver of an analog to digital converter's configuration.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
ADC resolution. Values can be 256, 1024 or 4096 depending whether the ADC
|
||||
is configured for 8, 10 or 12 bits.
|
||||
*/
|
||||
uint16_t adc_resolution;
|
||||
|
||||
/**
|
||||
VA_REF value in milli-Volts. This should be set to 2560 if internal VAREF
|
||||
is used.
|
||||
*/
|
||||
uint16_t va_ref;
|
||||
|
||||
} ace_adc_config_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The ppe_transforms_desc_t data structure is used by the ACE configurator to
|
||||
inform the ACE driver of the location of the "m" factor and "c" offset used
|
||||
by the PPE to perform a linear transform of the form y = m*x + c. This linear
|
||||
transform is used to apply calibration to the ADC samples. It can also include
|
||||
a user defined linear transform specified by the user using the ACE
|
||||
configurator. The factor and offset of the user defined transform is included
|
||||
in the default_m2 and default_c2 items.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
Offset into Post Processing Engine RAM where the linear transform m factor
|
||||
is stored.
|
||||
*/
|
||||
uint16_t m_ppe_offset;
|
||||
|
||||
/**
|
||||
Offset into Post Processing Engine RAM where the linear transform c offset
|
||||
is stored.
|
||||
*/
|
||||
uint16_t c_ppe_offset;
|
||||
|
||||
/**
|
||||
Default value of the user defined linear transform m2 factor.
|
||||
*/
|
||||
int16_t default_m2;
|
||||
|
||||
/**
|
||||
Default value of the user defined linear transform c2 offset.
|
||||
*/
|
||||
int16_t default_c2;
|
||||
} ppe_transforms_desc_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_ACE_CONFIGURATOR_H_ */
|
|
@ -0,0 +1,104 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* Manufacturing Test Data data structures.
|
||||
* This header files specified the layout of the various data structures used
|
||||
* to store manaufacturing test data within eNVM.
|
||||
*
|
||||
* SVN $Revision: 700 $
|
||||
* SVN $Date: 2009-03-13 13:22:03 +0000 (Fri, 13 Mar 2009) $
|
||||
*/
|
||||
#ifndef MTD_DATA_H
|
||||
#define MTD_DATA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Analog block specifications
|
||||
*/
|
||||
#define NB_OF_QUADS 6
|
||||
#define NB_OF_ABPS_PER_QUAD 2
|
||||
#define TOTAL_NB_OF_ABPS (NB_OF_QUADS * NB_OF_ABPS_PER_QUAD)
|
||||
#define NB_OF_ABPS_RANGES 4
|
||||
#define NB_OF_ANALOG_MODULES 3
|
||||
#define NB_OF_OBD_MODES 2
|
||||
#define NB_OF_QUADS_PER_MODULE 2
|
||||
#define NB_OF_CHOPPING_OPTIONS 2
|
||||
#define NB_OF_DIRECT_INPUTS_PER_ADC 4
|
||||
|
||||
#define NB_OF_ADC_CHANNELS 13
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* mtd_global_settings_t
|
||||
*------------------------------------------------------------------------------
|
||||
* This typedef specifies the layout of the data structure holding the
|
||||
* manufacturing test data global settings.
|
||||
*/
|
||||
typedef struct __mtd_global_settings_t
|
||||
{
|
||||
uint16_t crc16;
|
||||
uint8_t serial[6];
|
||||
uint32_t revision;
|
||||
uint16_t sram_repair[8];
|
||||
uint16_t varef_m;
|
||||
uint16_t spare;
|
||||
uint8_t big_dec;
|
||||
uint8_t reserved0;
|
||||
uint16_t reserved1;
|
||||
} mtd_global_settings_t;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* mtd_abps_trim_t
|
||||
*------------------------------------------------------------------------------
|
||||
* The following data structure is used to store ABPS trimming information.
|
||||
*/
|
||||
typedef struct __mtd_abps_trim_t
|
||||
{
|
||||
uint8_t dacdec;
|
||||
uint8_t negtrim_per4_per3b_gtdec;
|
||||
} mtd_abps_trim_t;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* mtd_calibration_mc_t
|
||||
*------------------------------------------------------------------------------
|
||||
* The following data structure is used to store M and C calibration
|
||||
* coefficients.
|
||||
*/
|
||||
typedef struct __mtd_calibration_mc_t
|
||||
{
|
||||
uint16_t m;
|
||||
uint16_t c;
|
||||
} mtd_calibration_mc_t;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* mtd_data_t
|
||||
*------------------------------------------------------------------------------
|
||||
* The following data structure is used to hold the full set of manufacturing
|
||||
* test data.
|
||||
*/
|
||||
typedef struct __mtd_data_t
|
||||
{
|
||||
mtd_global_settings_t global_settings;
|
||||
mtd_abps_trim_t abps_trimming[NB_OF_QUADS][NB_OF_ABPS_PER_QUAD][NB_OF_ABPS_RANGES];
|
||||
uint8_t odb_trimming[NB_OF_ANALOG_MODULES][NB_OF_OBD_MODES][NB_OF_CHOPPING_OPTIONS];
|
||||
mtd_calibration_mc_t abps_calibration[NB_OF_QUADS][NB_OF_ABPS_PER_QUAD][NB_OF_ABPS_RANGES];
|
||||
mtd_calibration_mc_t obd_calibration[NB_OF_ANALOG_MODULES][NB_OF_OBD_MODES][NB_OF_CHOPPING_OPTIONS];
|
||||
mtd_calibration_mc_t cm_calibration[NB_OF_QUADS];
|
||||
mtd_calibration_mc_t tm_calibration[NB_OF_QUADS];
|
||||
mtd_calibration_mc_t quads_direct_input_cal[NB_OF_QUADS][2];
|
||||
mtd_calibration_mc_t adc_direct_input_cal[NB_OF_ANALOG_MODULES][NB_OF_DIRECT_INPUTS_PER_ADC];
|
||||
uint16_t comparators_offsets[NB_OF_QUADS];
|
||||
uint32_t ccc_delays_cal;
|
||||
} mtd_data_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,103 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* crc32 source file.
|
||||
*
|
||||
* CRC-32-IEEE 802.3
|
||||
* x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 +
|
||||
* x^4 + x^2 + x + 1
|
||||
*
|
||||
* (c) Copyright 2007 Actel Corporation
|
||||
*
|
||||
* SVN $Revision: 2369 $
|
||||
* SVN $Date: 2010-03-01 18:31:45 +0000 (Mon, 01 Mar 2010) $
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
static const uint32_t crc32_table[] = {
|
||||
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL,
|
||||
0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL,
|
||||
0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL,
|
||||
0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL,
|
||||
0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
|
||||
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL,
|
||||
0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL,
|
||||
0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL,
|
||||
0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL,
|
||||
0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
|
||||
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL,
|
||||
0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL,
|
||||
0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL,
|
||||
0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL,
|
||||
0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
|
||||
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL,
|
||||
0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL,
|
||||
0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL,
|
||||
0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL,
|
||||
0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
|
||||
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL,
|
||||
0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL,
|
||||
0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL,
|
||||
0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL,
|
||||
0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
|
||||
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL,
|
||||
0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL,
|
||||
0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL,
|
||||
0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL,
|
||||
0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
|
||||
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL,
|
||||
0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL,
|
||||
0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL,
|
||||
0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL,
|
||||
0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
|
||||
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL,
|
||||
0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL,
|
||||
0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL,
|
||||
0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL,
|
||||
0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
|
||||
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL,
|
||||
0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL,
|
||||
0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates 32 bits CRC value of given data.
|
||||
*/
|
||||
uint32_t
|
||||
mss_mac_crc32
|
||||
(
|
||||
uint32_t value,
|
||||
const uint8_t *data,
|
||||
uint32_t data_length
|
||||
)
|
||||
{
|
||||
uint32_t a;
|
||||
|
||||
for(a=0; a<data_length; a++) {
|
||||
value = crc32_table[(value ^ data[a]) & 0xff] ^ (value >> 8);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates 32 bits CRC value of given data, using standart Ethernet CRC
|
||||
* function.
|
||||
*/
|
||||
uint32_t
|
||||
mss_ethernet_crc
|
||||
(
|
||||
const uint8_t *data,
|
||||
uint32_t data_length
|
||||
)
|
||||
{
|
||||
return mss_mac_crc32( 0xffffffffUL, data, data_length );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,46 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* crc32 header file.
|
||||
*
|
||||
* (c) Copyright 2007 Actel Corporation
|
||||
*
|
||||
* SVN $Revision: 2369 $
|
||||
* SVN $Date: 2010-03-01 18:31:45 +0000 (Mon, 01 Mar 2010) $
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __MSS_ETHERNET_MAC_CRC32_H
|
||||
#define __MSS_ETHERNET_MAC_CRC32_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Calculates 32 bits CRC value of given data.
|
||||
*/
|
||||
uint32_t
|
||||
mss_mac_crc32
|
||||
(
|
||||
uint32_t value,
|
||||
const uint8_t *data,
|
||||
uint32_t data_length
|
||||
);
|
||||
|
||||
/**
|
||||
* Calculates 32 bits CRC value of given data, using standart Ethernet CRC
|
||||
* function.
|
||||
*/
|
||||
uint32_t
|
||||
mss_ethernet_crc
|
||||
(
|
||||
const uint8_t *data,
|
||||
uint32_t data_length
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_ETHERNET_MAC_CRC32_H */
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,585 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* SmartFusion MSS Ethernet MAC header file.
|
||||
*
|
||||
* (c) Copyright 2007 Actel Corporation
|
||||
*
|
||||
* SVN $Revision: 2364 $
|
||||
* SVN $Date: 2010-03-01 17:58:41 +0000 (Mon, 01 Mar 2010) $
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __MSS_ETHERNET_MAC_H
|
||||
#define __MSS_ETHERNET_MAC_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/******************************** DEFINES *************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* Configure values.
|
||||
*/
|
||||
/**
|
||||
* Receive all.
|
||||
* When set, all incoming frames are received, regardless of their destination address.
|
||||
* An address check is performed, and the result of the check is written into the receive
|
||||
* descriptor.
|
||||
*/
|
||||
#define MSS_MAC_CFG_RECEIVE_ALL 0x00000001u
|
||||
|
||||
/**
|
||||
* Transmit threshold mode.
|
||||
* 1 - Transmit FIFO threshold set for 100 Mbps mode
|
||||
* 0 - Transmit FIFO threshold set for 10 Mbps mode
|
||||
* This bit can be changed only when a transmit process is in a stopped state.
|
||||
*/
|
||||
#define MSS_MAC_CFG_TRANSMIT_THRESHOLD_MODE 0x00000002u
|
||||
|
||||
/**
|
||||
* Store and forward.
|
||||
* When set, the transmission starts after a full packet is written into the transmit
|
||||
* FIFO, regardless of the current FIFO threshold level.
|
||||
* This bit can be changed only when the transmit process is in the stopped state.
|
||||
*/
|
||||
#define MSS_MAC_CFG_STORE_AND_FORWARD 0x00000004u
|
||||
|
||||
/**
|
||||
* Threshold control bits.
|
||||
* These bits, together with TTM, SF, and PS, control the threshold level for the
|
||||
* transmit FIFO.
|
||||
*/
|
||||
#define MSS_MAC_CFG_THRESHOLD_CONTROL_00 0x00000000u
|
||||
#define MSS_MAC_CFG_THRESHOLD_CONTROL_01 0x00000008u
|
||||
#define MSS_MAC_CFG_THRESHOLD_CONTROL_10 0x00000010u
|
||||
#define MSS_MAC_CFG_THRESHOLD_CONTROL_11 0x00000018u
|
||||
|
||||
/**
|
||||
* Full-duplex mode.
|
||||
* 0 - Half-duplex mode <br>
|
||||
* 1 - Forcing full-duplex mode <br>
|
||||
* Changing of this bit is allowed only when both the transmitter and receiver processes
|
||||
* are in the stopped state.
|
||||
*/
|
||||
#define MSS_MAC_CFG_FULL_DUPLEX_MODE 0x00000020u
|
||||
|
||||
/**
|
||||
* Pass all multicast.
|
||||
* When set, all frames with multicast destination addresses will be received, regardless
|
||||
* of the address check result.
|
||||
*/
|
||||
#define MSS_MAC_CFG_PASS_ALL_MULTICAST 0x00000040u
|
||||
|
||||
/**
|
||||
* Promiscuous mode.
|
||||
* When set, all frames will be received regardless of the address check result. An
|
||||
* address check is not performed.
|
||||
*/
|
||||
#define MSS_MAC_CFG_PROMISCUOUS_MODE 0x00000080u
|
||||
|
||||
/**
|
||||
* Inverse filtering (read-only).
|
||||
* If this bit is set when working in a perfect filtering mode, the receiver performs an
|
||||
* inverse filtering during the address check process.
|
||||
* The 'filtering type' bits of the setup frame determine the state of this bit.
|
||||
*/
|
||||
#define MSS_MAC_CFG_INVERSE_FILTERING 0x00000100u
|
||||
|
||||
/**
|
||||
* Pass bad frames.
|
||||
* When set, Core10/100 transfers all frames into the data buffers, regardless of the
|
||||
* receive errors. This allows the runt frames, collided fragments, and truncated frames
|
||||
* to be received.
|
||||
*/
|
||||
#define MSS_MAC_CFG_PASS_BAD_FRAMES 0x00000200u
|
||||
|
||||
/**
|
||||
* Hash-only filtering mode (read-only).
|
||||
* When set, Core10/100 performs an imperfect filtering over both the multicast and
|
||||
* physical addresses.
|
||||
* The 'filtering type' bits of the setup frame determine the state of this bit.
|
||||
*/
|
||||
#define MSS_MAC_CFG_HASH_ONLY_FILTERING_MODE 0x00000400u
|
||||
|
||||
/**
|
||||
* Hash/perfect receive filtering mode (read-only).
|
||||
* 0 - Perfect filtering of the incoming frames is performed according to the physical
|
||||
* addresses specified in a setup frame. <br>
|
||||
* 1 - Imperfect filtering over the frames with the multicast addresses is performed
|
||||
* according to the hash table specified in a setup frame. <br>
|
||||
* A physical address check is performed according to the CSR6.2 (HO, hash-only) bit.
|
||||
* When both the HO and HP bits are set, an imperfect filtering is performed on all of
|
||||
* the addresses.
|
||||
* The 'filtering type' bits of the setup frame determine the state of this bit.
|
||||
*/
|
||||
#define MSS_MAC_CFG_HASH_PERFECT_RECEIVE_FILTERING_MODE 0x00000800u
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Link status values.
|
||||
*/
|
||||
#define MSS_MAC_LINK_STATUS_LINK 0x0001u /**< Link up/down */
|
||||
#define MSS_MAC_LINK_STATUS_100MB 0x0002u /**< Connection is 100Mb/10Mb */
|
||||
#define MSS_MAC_LINK_STATUS_FDX 0x0004u /**< Connection is full/half duplex */
|
||||
|
||||
|
||||
/**
|
||||
* Size of the max packet that can be received/transmited.
|
||||
*/
|
||||
#define MSS_MAX_PACKET_SIZE 1514uL
|
||||
|
||||
/**
|
||||
* Size of a receive/transmit buffer.
|
||||
* Buffer size must be enough big to hold a full frame and must be multiple of
|
||||
* four. For rx buffer +4 bytes allocated for crc values. These bytes doesn't
|
||||
* copied to the user buffer.
|
||||
*/
|
||||
#define MSS_TX_BUFF_SIZE ((MSS_MAX_PACKET_SIZE + 3u) & (~(uint32_t)3))
|
||||
#define MSS_RX_BUFF_SIZE ((MSS_MAX_PACKET_SIZE + 7u) & (~(uint32_t)3))
|
||||
|
||||
/*******************************************************************************
|
||||
* Time out values.
|
||||
*/
|
||||
#define MSS_MAC_NONBLOCKING 0u
|
||||
#define MSS_MAC_BLOCKING 0xFFFFFFFFUL
|
||||
|
||||
/***************************************************************************//**
|
||||
* MAC events.
|
||||
*/
|
||||
#define MSS_MAC_EVENT_PACKET_SEND 1u
|
||||
#define MSS_MAC_EVENT_PACKET_RECEIVED 2u
|
||||
|
||||
/***************************************************************************//**
|
||||
* PHY addresses.
|
||||
*/
|
||||
#define MSS_PHY_ADDRESS_MIN 0u
|
||||
#define MSS_PHY_ADDRESS_MAX 31u
|
||||
#define MSS_PHY_ADDRESS_AUTO_DETECT 255u
|
||||
|
||||
/***************************************************************************//**
|
||||
* Listener function type defines the function prototype that might be followed
|
||||
* by MAC_isr which is triggered with each receive and transmit related interrupts.
|
||||
* Listener functions should follow the following prototype:
|
||||
* void MAC_Listener( uint32_t events );
|
||||
* The parameter is used to inform the listener function about the triggering event
|
||||
* or events. Events input to the system are:
|
||||
* #define MSS_MAC_EVENT_PACKET_SEND 1
|
||||
* #define MSS_MAC_EVENT_PACKET_RECEIVED 2
|
||||
* Listener function should be defined by the application using this driver if
|
||||
* needed. This function may be assigned to the driver using MAC_set_callback
|
||||
* routine and may be un assigned again by using the same routine with a NULL pointer
|
||||
* as the event listener function. It is recommended to use this property for interrupt
|
||||
* triggered systems and it is not recommended for polling mechanisms.
|
||||
*/
|
||||
typedef void (*MSS_MAC_callback_t)(uint32_t events);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Statistics counter identifiers are used with MAC_get_statistics routine to
|
||||
* receive the count of the requested errors/interrupts occurrences.
|
||||
*
|
||||
* MSS_MAC_RX_INTERRUPTS
|
||||
* Used to receive the number of receive interrupts occurred.
|
||||
*
|
||||
* MSS_MAC_RX_FILTERING_FAIL
|
||||
* Used to receive the number of received frames which did not pass the
|
||||
* address recognition process.
|
||||
*
|
||||
* MSS_MAC_RX_DESCRIPTOR_ERROR
|
||||
* Used to receive the number of occurrences of; no receive buffer was
|
||||
* available when trying to store the received data.
|
||||
*
|
||||
* MSS_MAC_RX_RUNT_FRAME
|
||||
* Used to receive the number of occurrences of; the frame is damaged by a
|
||||
* collision or by a premature termination before the end of a collision
|
||||
* window.
|
||||
*
|
||||
* MSS_MAC_RX_NOT_FIRST
|
||||
* Used to receive the number of occurrences of; start of the frame is not
|
||||
* the first descriptor of a frame.
|
||||
*
|
||||
* MSS_MAC_RX_NOT_LAST
|
||||
* Used to receive the number of occurrences of; end of the frame is not
|
||||
* the first descriptor of a frame.
|
||||
*
|
||||
* MSS_MAC_RX_FRAME_TOO_LONG
|
||||
* Used to receive the number of occurrences of; a current frame is longer
|
||||
* than maximum size of 1,518 bytes, as specified by 802.3.
|
||||
*
|
||||
* MSS_MAC_RX_COLLISION_SEEN
|
||||
* Used to receive the number of occurrences of; a late collision was seen
|
||||
* (collision after 64 bytes following SFD).
|
||||
*
|
||||
* MSS_MAC_RX_CRC_ERROR
|
||||
* Used to receive the number of occurrences of; a CRC error has occurred
|
||||
* in the received frame.
|
||||
*
|
||||
* MSS_MAC_RX_FIFO_OVERFLOW
|
||||
* Used to receive the number of frames not accepted due to the receive
|
||||
* FIFO overflow.
|
||||
*
|
||||
* MSS_MAC_RX_MISSED_FRAME
|
||||
* Used to receive the number of frames not accepted due to the
|
||||
* unavailability of the receive descriptor.
|
||||
*
|
||||
* MSS_MAC_TX_INTERRUPTS
|
||||
* Used to receive the number of transmit interrupts occurred.
|
||||
*
|
||||
* MSS_MAC_TX_LOSS_OF_CARRIER
|
||||
* Used to receive the number of occurrences of; a loss of the carrier
|
||||
* during a transmission.
|
||||
*
|
||||
* MSS_MAC_TX_NO_CARRIER
|
||||
* Used to receive the number of occurrences of; the carrier was not asserted
|
||||
* by an external transceiver during the transmission.
|
||||
*
|
||||
* MSS_MAC_TX_LATE_COLLISION
|
||||
* Used to receive the number of occurrences of; a collision was detected
|
||||
* after transmitting 64 bytes.
|
||||
*
|
||||
* MSS_MAC_TX_EXCESSIVE_COLLISION
|
||||
* Used to receive the number of occurrences of; the transmission was aborted
|
||||
* after 16 retries.
|
||||
*
|
||||
* MSS_MAC_TX_COLLISION_COUNT
|
||||
* Used to receive the number of collisions occurred.
|
||||
*
|
||||
* MSS_MAC_TX_UNDERFLOW_ERROR
|
||||
* Used to receive the number of occurrences of; the FIFO was empty during
|
||||
* the frame transmission.
|
||||
*/
|
||||
typedef enum {
|
||||
MSS_MAC_RX_INTERRUPTS,
|
||||
MSS_MAC_RX_FILTERING_FAIL,
|
||||
MSS_MAC_RX_DESCRIPTOR_ERROR,
|
||||
MSS_MAC_RX_RUNT_FRAME,
|
||||
MSS_MAC_RX_NOT_FIRST,
|
||||
MSS_MAC_RX_NOT_LAST,
|
||||
MSS_MAC_RX_FRAME_TOO_LONG,
|
||||
MSS_MAC_RX_COLLISION_SEEN,
|
||||
MSS_MAC_RX_CRC_ERROR,
|
||||
MSS_MAC_RX_FIFO_OVERFLOW,
|
||||
MSS_MAC_RX_MISSED_FRAME,
|
||||
|
||||
MSS_MAC_TX_INTERRUPTS,
|
||||
MSS_MAC_TX_LOSS_OF_CARRIER,
|
||||
MSS_MAC_TX_NO_CARRIER,
|
||||
MSS_MAC_TX_LATE_COLLISION,
|
||||
MSS_MAC_TX_EXCESSIVE_COLLISION,
|
||||
MSS_MAC_TX_COLLISION_COUNT,
|
||||
MSS_MAC_TX_UNDERFLOW_ERROR
|
||||
} mss_mac_statistics_id_t;
|
||||
|
||||
/******************************* FUNCTIONS ************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes an Ethernet MAC controller and data structures.
|
||||
* This function will prepare the Ethernet Controller for first time use in a
|
||||
* given hardware/software configuration. This function should be called before
|
||||
* any other Ethernet API functions are called.
|
||||
*
|
||||
* Initialization of registers - config registers, enable Tx/Rx interrupts,
|
||||
* enable Tx/Rx, initialize MAC addr, init PHY, autonegotiation, MAC address
|
||||
* filter table (unicast/multicast)/hash init
|
||||
*
|
||||
*/
|
||||
void
|
||||
MSS_MAC_init
|
||||
(
|
||||
uint8_t phy_address
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the configuration of the Ethernet Controller.
|
||||
* After the MAC_init function has been called, this API function can be
|
||||
* used to configure the various features of the Ethernet Controller.
|
||||
*
|
||||
* @param configuration The logical OR of the following values:
|
||||
* - #MSS_MAC_CFG_RECEIVE_ALL
|
||||
* - #MSS_MAC_CFG_TRANSMIT_THRESHOLD_MODE
|
||||
* - #MSS_MAC_CFG_STORE_AND_FORWARD
|
||||
* - #MSS_MAC_CFG_THRESHOLD_CONTROL_[00,01,10,11]
|
||||
* - #MSS_MAC_CFG_FULL_DUPLEX_MODE
|
||||
* - #MSS_MAC_CFG_PASS_ALL_MULTICAST
|
||||
* - #MSS_MAC_CFG_PROMISCUOUS_MODE
|
||||
* - #MSS_MAC_CFG_PASS_BAD_FRAMES
|
||||
* @see MAC_get_configuration()
|
||||
*/
|
||||
void
|
||||
MSS_MAC_configure
|
||||
(
|
||||
uint32_t configuration
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns the configuration of the Ethernet Controller.
|
||||
* After the MAC_init function has been called, this API function can be used to
|
||||
* get the configuration of the Ethernet Controller.
|
||||
*
|
||||
* @return The logical OR of the following values:
|
||||
* - #MSS_MAC_CFG_RECEIVE_ALL
|
||||
* - #MSS_MAC_CFG_TRANSMIT_THRESHOLD_MODE
|
||||
* - #MSS_MAC_CFG_STORE_AND_FORWARD
|
||||
* - #MSS_MAC_CFG_THRESHOLD_CONTROL_[00,01,10,11]
|
||||
* - #MSS_MAC_CFG_FULL_DUPLEX_MODE
|
||||
* - #MSS_MAC_CFG_PASS_ALL_MULTICAST
|
||||
* - #MSS_MAC_CFG_PROMISCUOUS_MODE
|
||||
* - #MSS_MAC_CFG_INVERSE_FILTERING
|
||||
* - #MSS_MAC_CFG_PASS_BAD_FRAMES
|
||||
* - #MSS_MAC_CFG_HASH_ONLY_FILTERING_MODE
|
||||
* - #MSS_MAC_CFG_HASH_PERFECT_RECEIVE_FILTERING_MODE
|
||||
* @see MAC_configure()
|
||||
*/
|
||||
int32_t
|
||||
MSS_MAC_get_configuration
|
||||
(
|
||||
void
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
Sends a packet from the uIP stack to the Ethernet Controller.
|
||||
The MSS_MAC_tx_packet() function is used to send a packet to the MSS Ethernet
|
||||
MAC. This function writes uip_len bytes of the packet contained in uip_buf into
|
||||
the transmit FIFO and then activates the transmitter for this packet. If space
|
||||
is available in the FIFO, the function will return once pac_len bytes of the
|
||||
packet have been placed into the FIFO and the transmitter has been started.
|
||||
This function will not wait for the transmission to complete.
|
||||
|
||||
@return
|
||||
The function returns zero if a timeout occurs otherwise it returns size of the packet.
|
||||
|
||||
@see MAC_rx_packet()
|
||||
*/
|
||||
|
||||
int32_t
|
||||
MSS_MAC_tx_packet
|
||||
(
|
||||
unsigned short usLength
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns available packet's size.
|
||||
*
|
||||
* @return Size of packet, bigger than 0, if a packet is available,
|
||||
* if not, returns 0.
|
||||
* @see MAC_rx_packet()
|
||||
*/
|
||||
int32_t
|
||||
MSS_MAC_rx_pckt_size
|
||||
(
|
||||
void
|
||||
);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Prepares the RX descriptor for receiving packets.
|
||||
*
|
||||
* @return void
|
||||
* @see MAC_rx_packet()
|
||||
*/
|
||||
void
|
||||
MSS_MAC_prepare_rx_descriptor
|
||||
(
|
||||
void
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Receives a packet from the Ethernet Controller into the uIP stack.
|
||||
* This function reads a packet from the receive FIFO of the controller and
|
||||
* places it into uip_buf.
|
||||
|
||||
* @return Size of packet if packet fits in uip_buf.
|
||||
* 0 if there is no received packet.
|
||||
* @see MAC_rx_pckt_size()
|
||||
* @see MAC_tx_packet()
|
||||
*/
|
||||
int32_t
|
||||
MSS_MAC_rx_packet
|
||||
(
|
||||
void
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
Receives a packet from the Ethernet Controller.
|
||||
The MSS_MAC_rx_packet_ptrset() function is very similar to the MSS_MAC_rx_packet()
|
||||
function, in that it receives data from the MSS Ethernet MAC. The difference
|
||||
is that it sets pacData to point to the memory buffer where the MSS Ethernet
|
||||
MAC copied the received packet instead of copying the received packet into a
|
||||
buffer provided by the application. After this function is called and data is
|
||||
used by the user application or copied to another buffer, the
|
||||
MSS_MAC_prepare_rx_descriptor() function must be called to free up the receive
|
||||
memory buffer used by the MSS Ethernet MAC
|
||||
|
||||
@param pacData
|
||||
The pacData parameter is a pointer to a memory buffer pointer. The uint8_t
|
||||
pointer pointed to by the pacData parameter will contain the address of the
|
||||
memory buffer containing the received packet after this function returns. The
|
||||
value of pacData is only valid if the return value is larger than zero,
|
||||
indicating that a packet was received.
|
||||
|
||||
@param time_out
|
||||
The time_out parameter is the timeout value for the transmission in milliseconds.
|
||||
The time_out parameter value can be one of the following values:
|
||||
• Unsigned integer greater than 0 and less than 0x01000000
|
||||
• MSS_MAC_BLOCKING – there will be no timeout.
|
||||
• MSS_MAC_NONBLOCKING – the function will return immediately if no packets
|
||||
have been received.
|
||||
|
||||
@return
|
||||
The function returns the size of the packet if the packet fits in pacData.
|
||||
Returns zero if there is no received packet.
|
||||
|
||||
@see MAC_rx_pckt_size()
|
||||
@see MAC_tx_packet()
|
||||
*/
|
||||
int32_t
|
||||
MSS_MAC_rx_packet_ptrset
|
||||
(
|
||||
uint8_t **pacData,
|
||||
uint32_t time_out
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns the status of connection by reading it from the PHY.
|
||||
*
|
||||
* @return the logical OR of the following values:
|
||||
* #MSS_MAC_LINK_STATUS_LINK - Link up/down
|
||||
* #MSS_MAC_LINK_STATUS_100MB - Connection is 100Mb/10Mb
|
||||
* #MSS_MAC_LINK_STATUS_FDX - Connection is full/half duplex
|
||||
* @see MAC_auto_setup_link()
|
||||
*/
|
||||
int32_t
|
||||
MSS_MAC_link_status
|
||||
(
|
||||
void
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Setups the link between PHY and MAC and returns the status of connection.
|
||||
*
|
||||
* @return the logical OR of the following values:
|
||||
* #MSS_MAC_LINK_STATUS_LINK - Link up/down
|
||||
* #MSS_MAC_LINK_STATUS_100MB - Connection is 100Mb/10Mb
|
||||
* #MSS_MAC_LINK_STATUS_FDX - Connection is full/half duplex
|
||||
* @see MAC_link_status()
|
||||
*/
|
||||
int32_t
|
||||
MSS_MAC_auto_setup_link
|
||||
(
|
||||
void
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets mac address.
|
||||
*
|
||||
* @param new_address Pointer to then new address value (6 bytes of data)
|
||||
* @see MAC_get_mac_address()
|
||||
*/
|
||||
void
|
||||
MSS_MAC_set_mac_address
|
||||
(
|
||||
const uint8_t *new_address
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns mac address.
|
||||
*
|
||||
* @param address Pointer to the parameter to receive the MAC address.
|
||||
* @see MAC_set_mac_address()
|
||||
*/
|
||||
void
|
||||
MSS_MAC_get_mac_address
|
||||
(
|
||||
uint8_t *address
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets mac address filters.
|
||||
* If less than 15 addresses are subscribed, system works on perfect filtering mode
|
||||
* else system works in hash table mode
|
||||
*
|
||||
* @param filter_count number of addresses
|
||||
* @param filters Pointer to addresses to be filtered
|
||||
*/
|
||||
void
|
||||
MSS_MAC_set_mac_filters
|
||||
(
|
||||
uint16_t filter_count,
|
||||
const uint8_t *filters
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets MAC event listener.
|
||||
* Sets the given event listener function to be triggered inside MAC_isr().
|
||||
* Assigning NULL pointer as the listener function will disable it.
|
||||
*
|
||||
* @param listener function pointer to a MSS_MAC_callback_t function
|
||||
* @see MAC_isr()
|
||||
*/
|
||||
void
|
||||
MSS_MAC_set_callback
|
||||
(
|
||||
MSS_MAC_callback_t listener
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns description of latest error happened.
|
||||
*
|
||||
* @return A string describing the error. This string must not be
|
||||
* modified by the application.
|
||||
*/
|
||||
const int8_t*
|
||||
MSS_MAC_last_error
|
||||
(
|
||||
void
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns statistics counter of stat_id identifier.
|
||||
*
|
||||
* @param stat_id Identifier of statistics counter.
|
||||
* @return Statistics counter of stat_id identifier.
|
||||
* On error returns 0.
|
||||
*/
|
||||
uint32_t
|
||||
MSS_MAC_get_statistics
|
||||
(
|
||||
mss_mac_statistics_id_t stat_id
|
||||
);
|
||||
|
||||
/*
|
||||
* Ensure uip_buf is pointing to a valid and free buffer before any transmissions
|
||||
* initiated by the uIP stack occur.
|
||||
*/
|
||||
unsigned char *MSS_MAC_GetTxDescriptor( void );
|
||||
|
||||
/*
|
||||
* A buffer is no longer required by the application. Hand it back to the
|
||||
* control of the MAC hardware.
|
||||
*/
|
||||
void MSS_MAC_ReleaseBuffer( unsigned char *pucBuffer );
|
||||
|
||||
/*
|
||||
* The double Tx has completed. Hand back the Tx buffer to the control of
|
||||
* the MAC hardware.
|
||||
*/
|
||||
void MSS_MAC_TxBufferCompleted( void );
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_ETHERNET_MAC_H */
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* SmartFusion MSS Ethenet MAC configuration header file.
|
||||
*
|
||||
* (c) Copyright 2007 Actel Corporation
|
||||
*
|
||||
* SVN $Revision: 2299 $
|
||||
* SVN $Date: 2010-02-24 21:21:12 +0000 (Wed, 24 Feb 2010) $
|
||||
*******************************************************************************/
|
||||
#ifndef __MSS_ETHERNET_MAC_CONF_H
|
||||
#define __MSS_ETHERNET_MAC_CONF_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Default MAC address
|
||||
*/
|
||||
#define DEFAULT_MAC_ADDRESS configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5
|
||||
#define BROADCAST_MAC_ADDRESS 0xFFu,0xFFu,0xFFu,0xFFu,0xFFu,0xFFu
|
||||
|
||||
/**
|
||||
* Descriptor byte ordering mode.
|
||||
* 1 - Big-endian mode used for data descriptors <br>
|
||||
* 0 - Little-endian mode used for data descriptors <br>
|
||||
*/
|
||||
#define DESCRIPTOR_BYTE_ORDERING_MODE LITTLEENDIAN
|
||||
|
||||
/**
|
||||
* Big/little endian.
|
||||
* Selects the byte-ordering mode used by the data buffers.
|
||||
* 1 - Big-endian mode used for the data buffers
|
||||
* 0 - Little-endian mode used for the data buffers
|
||||
*/
|
||||
#define BUFFER_BYTE_ORDERING_MODE LITTLEENDIAN
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_ETHERNET_MAC_CONF_H */
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* SmartFusion MSS Ethernet MAC internal defines header file.
|
||||
*
|
||||
* (c) Copyright 2007 Actel Corporation
|
||||
*
|
||||
* SVN $Revision: 2299 $
|
||||
* SVN $Date: 2010-02-24 21:21:12 +0000 (Wed, 24 Feb 2010) $
|
||||
*******************************************************************************/
|
||||
#ifndef __MSS_ETHERNET_MAC_DESC_H
|
||||
#define __MSS_ETHERNET_MAC_DESC_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Receive descriptor bits
|
||||
*/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Ownership bit.
|
||||
* 1 - Core10/100 owns the descriptor. <br>
|
||||
* 0 - The host owns the descriptor. <br>
|
||||
* Core10/100 will clear this bit when it completes a current frame reception or
|
||||
* when the data buffers associated with a given descriptor are already full.
|
||||
*/
|
||||
#define RDES0_OWN 0x80000000UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Filtering fail.
|
||||
* When set, indicates that a received frame did not pass the address recognition process.
|
||||
* This bit is valid only for the last descriptor of the frame (RDES0.8 set), when the CSR6.30 (receive all) bit
|
||||
* is set and the frame is at least 64 bytes long.
|
||||
*/
|
||||
#define RDES0_FF 0x40000000UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frame length.
|
||||
* Indicates the length, in bytes, of the data transferred into a host memory for a given frame
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set and RDES0.14 (descriptor error) is cleared.
|
||||
*/
|
||||
#define RDES0_FL_MASK 0x00003FFFUL
|
||||
#define RDES0_FL_OFFSET 16
|
||||
|
||||
/***************************************************************************//**
|
||||
* Error summary.
|
||||
* This bit is a logical OR of the following bits:
|
||||
* RDES0.1 - CRC error
|
||||
* RDES0.6 - Collision seen
|
||||
* RDES0.7 - Frame too long
|
||||
* RDES0.11 - Runt frame
|
||||
* RDES0.14 - Descriptor error
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set.
|
||||
*/
|
||||
#define RDES0_ES 0x00008000UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Descriptor error.
|
||||
* Set by Core10/100 when no receive buffer was available when trying to store the received data.
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set.
|
||||
*/
|
||||
#define RDES0_DE 0x00004000UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Runt frame.
|
||||
* When set, indicates that the frame is damaged by a collision or by a premature termination before the end
|
||||
* of a collision window.
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set.
|
||||
*/
|
||||
#define RDES0_RF 0x00000800UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Multicast frame.
|
||||
* When set, indicates that the frame has a multicast address.
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set.
|
||||
*/
|
||||
#define RDES0_MF 0x00000400UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* First descriptor.
|
||||
* When set, indicates that this is the first descriptor of a frame.
|
||||
*/
|
||||
#define RDES0_FS 0x00000200UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Last descriptor.
|
||||
* When set, indicates that this is the last descriptor of a frame.
|
||||
*/
|
||||
#define RDES0_LS 0x00000100UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frame too long.
|
||||
* When set, indicates that a current frame is longer than maximum size of 1,518 bytes, as specified by 802.3.
|
||||
* TL (frame too long) in the receive descriptor has been set when the received frame is longer than
|
||||
* 1,518 bytes. This flag is valid in all receive descriptors when multiple descriptors are used for one frame.
|
||||
*/
|
||||
#define RDES0_TL 0x00000080UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Collision seen.
|
||||
* When set, indicates that a late collision was seen (collision after 64 bytes following SFD).
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set.
|
||||
*/
|
||||
#define RDES0_CS 0x00000040UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frame type.
|
||||
* When set, indicates that the frame has a length field larger than 1,500 (Ethernet-type frame). When
|
||||
* cleared, indicates an 802.3-type frame.
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set.
|
||||
* Additionally, FT is invalid for runt frames shorter than 14 bytes.
|
||||
*/
|
||||
#define RDES0_FT 0x00000020UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Report on MII error.
|
||||
* When set, indicates that an error has been detected by a physical layer chip connected through the MII
|
||||
* interface.
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set.
|
||||
*/
|
||||
#define RDES0_RE 0x00000008UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dribbling bit.
|
||||
* When set, indicates that the frame was not byte-aligned.
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set.
|
||||
*/
|
||||
#define RDES0_DB 0x00000004UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* CRC error.
|
||||
* When set, indicates that a CRC error has occurred in the received frame.
|
||||
* This bit is valid only when RDES0.8 (last descriptor) is set.
|
||||
* Additionally, CE is not valid when the received frame is a runt frame.
|
||||
*/
|
||||
#define RDES0_CE 0x00000002UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* This bit is reset for frames with a legal length.
|
||||
*/
|
||||
#define RDES0_ZERO 0x00000001UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Receive end of ring.
|
||||
* When set, indicates that this is the last descriptor in the receive descriptor ring. Core10/100 returns to the
|
||||
* first descriptor in the ring, as specified by CSR3 (start of receive list address).
|
||||
*/
|
||||
#define RDES1_RER 0x02000000UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Second address chained.
|
||||
* When set, indicates that the second buffer's address points to the next descriptor and not to the data buffer.
|
||||
* Note that RER takes precedence over RCH.
|
||||
*/
|
||||
#define RDES1_RCH 0x01000000UL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Buffer 2 size.
|
||||
* Indicates the size, in bytes, of memory space used by the second data buffer. This number must be a
|
||||
* multiple of four. If it is 0, Core10/100 ignores the second data buffer and fetches the next data descriptor.
|
||||
* This number is valid only when RDES1.24 (second address chained) is cleared.
|
||||
*/
|
||||
#define RDES1_RBS2_MASK 0x7FF
|
||||
#define RDES1_RBS2_OFFSET 11
|
||||
|
||||
/***************************************************************************//**
|
||||
* Buffer 1 size
|
||||
* Indicates the size, in bytes, of memory space used by the first data buffer. This number must be a multiple of
|
||||
* four. If it is 0, Core10/100 ignores the first data buffer and uses the second data buffer.
|
||||
*/
|
||||
#define RDES1_RBS1_MASK 0x7FF
|
||||
#define RDES1_RBS1_OFFSET 0
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Transmit descriptor bits
|
||||
*/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Ownership bit.
|
||||
* 1 - Core10/100 owns the descriptor.
|
||||
* 0 - The host owns the descriptor.
|
||||
* Core10/100 will clear this bit when it completes a current frame transmission or when the data buffers
|
||||
* associated with a given descriptor are empty.
|
||||
*/
|
||||
#define TDES0_OWN 0x80000000uL
|
||||
|
||||
/***************************************************************************//**
|
||||
* Error summary.
|
||||
* This bit is a logical OR of the following bits:
|
||||
* TDES0.1 - Underflow error
|
||||
* TDES0.8 - Excessive collision error
|
||||
* TDES0.9 - Late collision
|
||||
* TDES0.10 - No carrier
|
||||
* TDES0.11 - Loss of carrier
|
||||
* This bit is valid only when TDES1.30 (last descriptor) is set.
|
||||
*/
|
||||
#define TDES0_ES ((uint32_t)1 << 15)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Loss of carrier.
|
||||
* When set, indicates a loss of the carrier during a transmission.
|
||||
* This bit is valid only when TDES1.30 (last descriptor) is set.
|
||||
*/
|
||||
#define TDES0_LO ((uint32_t)1 << 11)
|
||||
|
||||
/***************************************************************************//**
|
||||
* No carrier.
|
||||
* When set, indicates that the carrier was not asserted by an external transceiver during the transmission.
|
||||
* This bit is valid only when TDES1.30 (last descriptor) is set.
|
||||
*/
|
||||
#define TDES0_NC ((uint32_t)1 << 10)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Late collision.
|
||||
* When set, indicates that a collision was detected after transmitting 64 bytes.
|
||||
* This bit is not valid when TDES0.1 (underflow error) is set.
|
||||
* This bit is valid only when TDES1.30 (last descriptor) is set.
|
||||
*/
|
||||
#define TDES0_LC ((uint32_t)1 << 9)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Excessive collisions.
|
||||
* When set, indicates that the transmission was aborted after 16 retries.
|
||||
* This bit is valid only when TDES1.30 (last descriptor) is set.
|
||||
*/
|
||||
#define TDES0_EC ((uint32_t)1 << 8)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Collision count.
|
||||
* This field indicates the number of collisions that occurred before the end of a frame transmission.
|
||||
* This value is not valid when TDES0.8 (excessive collisions bit) is set.
|
||||
* This bit is valid only when TDES1.30 (last descriptor) is set.
|
||||
*/
|
||||
#define TDES0_CC_MASK 0xFu
|
||||
#define TDES0_CC_OFFSET 3u
|
||||
|
||||
/***************************************************************************//**
|
||||
* Underflow error.
|
||||
* When set, indicates that the FIFO was empty during the frame transmission.
|
||||
* This bit is valid only when TDES1.30 (last descriptor) is set.
|
||||
*/
|
||||
#define TDES0_UF ((uint32_t)1 << 1)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Deferred.
|
||||
* When set, indicates that the frame was deferred before transmission. Deferring occurs if the carrier is detected
|
||||
* when the transmission is ready to start.
|
||||
* This bit is valid only when TDES1.30 (last descriptor) is set.
|
||||
*/
|
||||
#define TDES0_DE (1)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Interrupt on completion.
|
||||
* Setting this flag instructs Core10/100 to set CSR5.0 (transmit interrupt) immediately after processing a
|
||||
* current frame.
|
||||
* This bit is valid when TDES1.30 (last descriptor) is set or for a setup packet.
|
||||
*/
|
||||
#define TDES1_IC ((uint32_t)1 << 31)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Last descriptor.
|
||||
* When set, indicates the last descriptor of the frame.
|
||||
*/
|
||||
#define TDES1_LS ((uint32_t)1 << 30)
|
||||
|
||||
/***************************************************************************//**
|
||||
* First descriptor.
|
||||
* When set, indicates the first descriptor of the frame.
|
||||
*/
|
||||
#define TDES1_FS ((uint32_t)1 << 29)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Filtering type.
|
||||
* This bit, together with TDES0.22 (FT0), controls a current filtering mode.
|
||||
* This bit is valid only for the setup frames.
|
||||
*/
|
||||
#define TDES1_FT1 ((uint32_t)1 << 28)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Setup packet.
|
||||
* When set, indicates that this is a setup frame descriptor.
|
||||
*/
|
||||
#define TDES1_SET ((uint32_t)1 << 27)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Add CRC disable.
|
||||
* When set, Core10/100 does not append the CRC value at the end of the frame. The exception is when the
|
||||
* frame is shorter than 64 bytes and automatic byte padding is enabled. In that case, the CRC field is added,
|
||||
* despite the state of the AC flag.
|
||||
*/
|
||||
#define TDES1_AC ((uint32_t)1 << 26)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Transmit end of ring.
|
||||
* When set, indicates the last descriptor in the descriptor ring.
|
||||
*/
|
||||
#define TDES1_TER ((uint32_t)1 << 25)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Second address chained.
|
||||
* When set, indicates that the second descriptor's address points to the next descriptor and not to the data
|
||||
* buffer.
|
||||
* This bit is valid only when TDES1.25 (transmit end of ring) is reset.
|
||||
*/
|
||||
#define TDES1_TCH ((uint32_t)1 << 24)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Disabled padding.
|
||||
* When set, automatic byte padding is disabled. Core10/100 normally appends the PAD field after the INFO
|
||||
* field when the size of an actual frame is less than 64 bytes. After padding bytes, the CRC field is also
|
||||
* inserted, despite the state of the AC flag. When DPD is set, no padding bytes are appended.
|
||||
*/
|
||||
#define TDES1_DPD ((uint32_t)1 << 23)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Filtering type.
|
||||
* This bit, together with TDES0.28 (FT1), controls the current filtering mode.
|
||||
* This bit is valid only when the TDES1.27 (SET) bit is set.
|
||||
*/
|
||||
#define TDES1_FT0 ((uint32_t)1 << 22)
|
||||
|
||||
/***************************************************************************//**
|
||||
* Buffer 2 size.
|
||||
* Indicates the size, in bytes, of memory space used by the second data buffer. If it is zero, Core10/100 ignores
|
||||
* the second data buffer and fetches the next data descriptor.
|
||||
* This bit is valid only when TDES1.24 (second address chained) is cleared.
|
||||
*/
|
||||
#define TDES1_TBS2_MASK 0x7FF
|
||||
#define TDES1_TBS2_OFFSET 11u
|
||||
|
||||
/***************************************************************************//**
|
||||
* Buffer 1 size.
|
||||
* Indicates the size, in bytes, of memory space used by the first data buffer. If it is 0, Core10/100 ignores the
|
||||
* first data buffer and uses the second data buffer.
|
||||
*/
|
||||
#define TDES1_TBS1_MASK 0x7FF
|
||||
#define TDES1_TBS1_OFFSET 0u
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_ETHERNET_MAC_DESC_H */
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,26 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2007 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* Actel:Firmware:MSS_Ethernet_MAC_Driver:2.0.103 configuration.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ACTEL__FIRMWARE__MSS_ETHERNET_MAC_DRIVER__2_0_103_CONFIGURATION_HEADER
|
||||
#define ACTEL__FIRMWARE__MSS_ETHERNET_MAC_DRIVER__2_0_103_CONFIGURATION_HEADER
|
||||
|
||||
|
||||
#define CORE_VENDOR "Actel"
|
||||
#define CORE_LIBRARY "Firmware"
|
||||
#define CORE_NAME "MSS_Ethernet_MAC_Driver"
|
||||
#define CORE_VERSION "2.0.103"
|
||||
|
||||
#define BUS_ARBITRATION_SCHEME 0
|
||||
#define PROGRAMMABLE_BURST_LENGTH 0
|
||||
#define RX_RING_SIZE 4
|
||||
#define SETUP_FRAME_TIME_OUT 10000
|
||||
#define STATE_CHANGE_TIME_OUT 10000
|
||||
#define TX_RING_SIZE 2
|
||||
|
||||
#endif // ACTEL__FIRMWARE__MSS_ETHERNET_MAC_DRIVER__2_0_103_CONFIGURATION_HEADER
|
||||
|
|
@ -0,0 +1,390 @@
|
|||
/***************************************************************************//**
|
||||
* PHY access methods for DP83848C.
|
||||
* The implementation in this file is specific to the DP83848C,
|
||||
* If a different PHY support is required the PHY specific registers must
|
||||
* be updated.
|
||||
* (c) Copyright 2007 Actel Corporation
|
||||
*
|
||||
* SVN $Revision: 2324 $
|
||||
* SVN $Date: 2010-02-26 10:47:36 +0000 (Fri, 26 Feb 2010) $
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include "mss_ethernet_mac.h"
|
||||
#include "mss_ethernet_mac_regs.h"
|
||||
|
||||
#include "phy.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
extern MAC_instance_t g_mss_mac;
|
||||
|
||||
/***************************** MDIO FUNCTIONS *********************************/
|
||||
|
||||
/* Defines ********************************************************************/
|
||||
#define MDIO_START 0x00004000UL
|
||||
#define MDIO_READ 0x00002000UL
|
||||
#define MDIO_WRITE 0x00001002UL
|
||||
#define MDIO_ADDR_OFFSET 7UL
|
||||
#define MDIO_ADDR_MASK 0x00000f80UL
|
||||
#define MDIO_REG_ADDR_OFFSET 2UL
|
||||
#define MDIO_REG_ADDR_MASK 0x0000007cUL
|
||||
#define PREAMBLECOUNT 32UL
|
||||
#define ONEMICROSECOND 20UL
|
||||
|
||||
typedef enum {
|
||||
MDIO_CMD_READ,
|
||||
MDIO_CMD_WRITE
|
||||
}mdio_cmd_t;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set clock high or low.
|
||||
*/
|
||||
static void
|
||||
MDIO_management_clock
|
||||
(
|
||||
int32_t clock
|
||||
)
|
||||
{
|
||||
int32_t volatile a;
|
||||
|
||||
MAC_BITBAND->CSR9_MDC = (uint32_t)clock;
|
||||
|
||||
/* delay for 1us */
|
||||
for( a = 0; a < ONEMICROSECOND; a++ ){}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Send read or write command to PHY.
|
||||
*/
|
||||
static void
|
||||
MDIO_send_cmd
|
||||
(
|
||||
uint8_t regad,
|
||||
mdio_cmd_t mdio_cmd
|
||||
)
|
||||
{
|
||||
int32_t i;
|
||||
uint16_t mask, data;
|
||||
|
||||
/* enable MII output */
|
||||
MAC_BITBAND->CSR9_MDEN = 1;
|
||||
|
||||
/* send 32 1's preamble */
|
||||
MAC_BITBAND->CSR9_MDO = 1;
|
||||
for (i = 0; i < PREAMBLECOUNT; i++) {
|
||||
MDIO_management_clock( 0 );
|
||||
MDIO_management_clock( 1 );
|
||||
}
|
||||
|
||||
/* calculate data bits */
|
||||
data = MDIO_START |
|
||||
(( mdio_cmd == MDIO_CMD_READ ) ? MDIO_READ : MDIO_WRITE ) |
|
||||
((g_mss_mac.phy_address << MDIO_ADDR_OFFSET) & MDIO_ADDR_MASK) |
|
||||
((regad << MDIO_REG_ADDR_OFFSET) & MDIO_REG_ADDR_MASK);
|
||||
|
||||
/* sent out */
|
||||
for( mask = 0x00008000L; mask>0; mask >>= 1 )
|
||||
{
|
||||
if ((mask == 0x2) && (mdio_cmd == MDIO_CMD_READ)) {
|
||||
/* enable MII input */
|
||||
MAC_BITBAND->CSR9_MDEN = 0;
|
||||
}
|
||||
|
||||
MDIO_management_clock( 0 );
|
||||
|
||||
/* prepare MDO */
|
||||
MAC_BITBAND->CSR9_MDO = (uint32_t)((mask & data) != 0 ? 1UL : 0UL);
|
||||
|
||||
MDIO_management_clock( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Reads a PHY register.
|
||||
*/
|
||||
static uint16_t
|
||||
MDIO_read
|
||||
(
|
||||
uint8_t regad
|
||||
)
|
||||
{
|
||||
uint16_t mask;
|
||||
uint16_t data;
|
||||
|
||||
MDIO_send_cmd( regad, MDIO_CMD_READ);
|
||||
|
||||
/* read data */
|
||||
data = 0;
|
||||
for( mask = 0x00008000L; mask>0; mask >>= 1 )
|
||||
{
|
||||
MDIO_management_clock( 0 );
|
||||
|
||||
/* read MDI */
|
||||
if(MAC_BITBAND-> CSR9_MDI != 0){
|
||||
data |= mask;
|
||||
}
|
||||
|
||||
MDIO_management_clock( 1 );
|
||||
}
|
||||
|
||||
MDIO_management_clock( 0 );
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Writes to a PHY register.
|
||||
*/
|
||||
static void
|
||||
MDIO_write
|
||||
(
|
||||
uint8_t regad,
|
||||
uint16_t data
|
||||
)
|
||||
{
|
||||
uint16_t mask;
|
||||
|
||||
MDIO_send_cmd(regad, MDIO_CMD_WRITE);
|
||||
|
||||
/* write data */
|
||||
for( mask = 0x00008000L; mask>0; mask >>= 1 )
|
||||
{
|
||||
MDIO_management_clock( 0 );
|
||||
|
||||
/* prepare MDO */
|
||||
MAC_BITBAND->CSR9_MDO = (uint32_t)((mask & data) != 0 ? 1UL : 0UL);
|
||||
|
||||
MDIO_management_clock( 1 );
|
||||
}
|
||||
|
||||
MDIO_management_clock( 0 );
|
||||
}
|
||||
|
||||
|
||||
/****************************** PHY FUNCTIONS *********************************/
|
||||
|
||||
/* Defines ********************************************************************/
|
||||
|
||||
/* Base registers */
|
||||
#define PHYREG_MIIMCR 0x00 /**< MII Management Control Register */
|
||||
#define MIIMCR_RESET (1<<15)
|
||||
#define MIIMCR_LOOPBACK (1<<14)
|
||||
#define MIIMCR_SPEED_SELECT (1<<13)
|
||||
#define MIIMCR_ENABLE_AUTONEGOTIATION (1<<12)
|
||||
#define MIIMCR_RESTART_AUTONEGOTIATION (1<<9)
|
||||
#define MIIMCR_DUPLEX_MODE (1<<8)
|
||||
#define MIIMCR_COLLISION_TEST (1<<7)
|
||||
|
||||
#define PHYREG_MIIMSR 0x01 /**< MII Management Status Register */
|
||||
#define MIIMSR_ANC (1<<5) /**< Auto-Negotiation Completed. */
|
||||
#define MIIMSR_LINK (1<<2) /**< Link is established. */
|
||||
|
||||
#define PHYREG_PHYID1R 0x02 /**< PHY Identifier 1 Register */
|
||||
#define PHYREG_PHYID2R 0x03 /**< PHY Identifier 2 Register */
|
||||
|
||||
#define PHYREG_ANAR 0x04 /**< Auto-Negotiation Advertisement Register */
|
||||
#define ANAR_100FD (1<<8)
|
||||
#define ANAR_100HD (1<<7)
|
||||
#define ANAR_10FD (1<<6)
|
||||
#define ANAR_10HD (1<<5)
|
||||
|
||||
#define PHYREG_ANLPAR 0x05 /**< Auto-Negotiation Link Partner Ability Register */
|
||||
#define PHYREG_ANER 0x06 /**< Auto-Negotiation Expansion Register */
|
||||
#define PHYREG_NPAR 0x07 /**< Next Page Advertisement Register */
|
||||
/* 0x08- 0x0F Reserved */
|
||||
#define PHYREG_MFR 0x10 /**< Miscellaneous Features Register */
|
||||
#define PHYREG_ICSR 0x11 /**< Interrupt Control/Status Register */
|
||||
|
||||
#define PHYREG_DR 0x12 /**< Diagnostic Register */
|
||||
#define DR_DPLX (1<<11)
|
||||
#define DR_DATA_RATE (1<<10)
|
||||
|
||||
#define PHYREG_PMLR 0x13 /**< Power Management & Loopback Register */
|
||||
/* 0x14 Reserved */
|
||||
#define PHYREG_MCR 0x15 /**< Mode Control Register */
|
||||
#define MCR_LED_SEL (1<<9)
|
||||
/* 0x16 Reserved */
|
||||
#define PHYREG_DCR 0x17 /**< Disconnect Counter */
|
||||
#define PHYREG_RECR 0x18 /**< Receive Error Counter */
|
||||
/* 0x19-0x1F Reserved */
|
||||
|
||||
/***************************************************************************//**
|
||||
* Probe used PHY.
|
||||
*
|
||||
* return PHY address. If PHY don't fount, returns 255.
|
||||
*/
|
||||
uint8_t PHY_probe( void )
|
||||
{
|
||||
uint8_t phy;
|
||||
uint8_t phy_found;
|
||||
uint16_t reg;
|
||||
|
||||
phy_found = 0;
|
||||
for (phy = MSS_PHY_ADDRESS_MIN; phy <= MSS_PHY_ADDRESS_MAX; phy++) {
|
||||
g_mss_mac.phy_address = phy;
|
||||
|
||||
reg = MDIO_read( PHYREG_PHYID1R );
|
||||
|
||||
if ((reg != 0x0000ffffUL) && (reg != 0x00000000UL)) {
|
||||
phy_found = 1;
|
||||
phy = MSS_PHY_ADDRESS_MAX + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( phy_found == 0 ) {
|
||||
g_mss_mac.phy_address = MSS_PHY_ADDRESS_AUTO_DETECT;
|
||||
}
|
||||
return g_mss_mac.phy_address;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Resets the PHY.
|
||||
*/
|
||||
void PHY_reset( void )
|
||||
{
|
||||
MDIO_write( PHYREG_MIIMCR, MIIMCR_RESET );
|
||||
MDIO_write( PHYREG_MIIMCR,
|
||||
MIIMCR_ENABLE_AUTONEGOTIATION |
|
||||
MIIMCR_RESTART_AUTONEGOTIATION |
|
||||
MIIMCR_COLLISION_TEST );
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Restarts PHY auto-negotiation and wait until it's over.
|
||||
*/
|
||||
void PHY_auto_negotiate( void )
|
||||
{
|
||||
uint16_t reg;
|
||||
|
||||
reg = MDIO_read( PHYREG_MIIMCR );
|
||||
MDIO_write( PHYREG_MIIMCR,
|
||||
(uint16_t)( MIIMCR_ENABLE_AUTONEGOTIATION |
|
||||
MIIMCR_RESTART_AUTONEGOTIATION |
|
||||
reg) );
|
||||
|
||||
for( ;; ) {
|
||||
reg = MDIO_read( PHYREG_MIIMSR );
|
||||
if( (reg & MIIMSR_ANC) != 0 ) {
|
||||
break;
|
||||
} else {
|
||||
vTaskDelay( 200 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns link status.
|
||||
*
|
||||
* @return #MAC_LINK_STATUS_LINK if link is up.
|
||||
*/
|
||||
uint8_t PHY_link_status( void )
|
||||
{
|
||||
uint8_t retval = 0;
|
||||
if(( MDIO_read( PHYREG_MIIMSR ) & MIIMSR_LINK ) != 0 ){
|
||||
retval = MSS_MAC_LINK_STATUS_LINK;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns link type.
|
||||
*
|
||||
* @return the logical OR of the following values:
|
||||
* #MAC_LINK_STATUS_100MB - Connection is 100Mb
|
||||
* #MAC_LINK_STATUS_FDX - Connection is full duplex
|
||||
*/
|
||||
uint8_t PHY_link_type( void )
|
||||
{
|
||||
uint16_t diagnostic;
|
||||
uint8_t type = 0;
|
||||
|
||||
diagnostic = MDIO_read( PHYREG_DR );
|
||||
|
||||
if( (diagnostic & DR_DPLX) != 0 ) {
|
||||
type = MSS_MAC_LINK_STATUS_FDX;
|
||||
}
|
||||
|
||||
if( (diagnostic & DR_DATA_RATE) != 0 ) {
|
||||
type |= MSS_MAC_LINK_STATUS_100MB;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets link type.
|
||||
*/
|
||||
void
|
||||
PHY_set_link_type
|
||||
(
|
||||
uint8_t type
|
||||
)
|
||||
{
|
||||
uint16_t reg;
|
||||
|
||||
reg = MDIO_read( PHYREG_ANAR );
|
||||
reg |= ANAR_100FD | ANAR_100HD | ANAR_10FD | ANAR_10HD;
|
||||
|
||||
if( (type & MSS_MAC_LINK_STATUS_100MB) == 0 ) {
|
||||
reg &= ~(ANAR_100FD | ANAR_100HD);
|
||||
}
|
||||
|
||||
if( (type & MSS_MAC_LINK_STATUS_FDX) == 0 ) {
|
||||
reg &= ~(ANAR_100FD | ANAR_10FD);
|
||||
}
|
||||
|
||||
MDIO_write( PHYREG_ANAR, reg );
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Puts the Phy in Loopback mode
|
||||
*/
|
||||
uint16_t
|
||||
PHY_set_loopback
|
||||
(
|
||||
uint8_t enable
|
||||
)
|
||||
{
|
||||
|
||||
uint16_t reg = 0;
|
||||
|
||||
|
||||
reg = MDIO_read( PHYREG_MIIMCR );
|
||||
// If set to one we need to set the LOCAL Phy loopback
|
||||
if(enable == 1)
|
||||
reg |= MIIMCR_LOOPBACK;
|
||||
else // else we want to clear the bit..
|
||||
reg ^= MIIMCR_LOOPBACK;
|
||||
|
||||
|
||||
MDIO_write( PHYREG_MIIMCR,reg );
|
||||
reg = MDIO_read( PHYREG_MIIMCR );
|
||||
|
||||
return reg;
|
||||
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************** END OF FILE *********************************/
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/***************************************************************************//**
|
||||
* PHY access methods.
|
||||
*
|
||||
* (c) Copyright 2007 Actel Corporation
|
||||
*
|
||||
* SVN $Revision: 2293 $
|
||||
* SVN $Date: 2010-02-24 13:52:02 +0000 (Wed, 24 Feb 2010) $
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __MSS_ETHERNET_MAC_PHY_H
|
||||
#define __MSS_ETHERNET_MAC_PHY_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Resets the PHY.
|
||||
*/
|
||||
void PHY_reset( void );
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Restarts PHY auto-negotiation and wait until it's over.
|
||||
*/
|
||||
void PHY_auto_negotiate( void );
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Probe used PHY.
|
||||
*
|
||||
* return PHY address. If PHY don't fount, returns 255.
|
||||
*/
|
||||
uint8_t PHY_probe( void );
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns link status.
|
||||
*
|
||||
* @return #MAC_LINK_STATUS_LINK if link is up.
|
||||
*/
|
||||
uint8_t PHY_link_status( void );
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns link type.
|
||||
*
|
||||
* @return the logical OR of the following values:
|
||||
* #MAC_LINK_STATUS_100MB - Connection is 100Mb
|
||||
* #MAC_LINK_STATUS_FDX - Connection is full duplex
|
||||
*/
|
||||
uint8_t PHY_link_type( void );
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets link type.
|
||||
*/
|
||||
void
|
||||
PHY_set_link_type
|
||||
(
|
||||
uint8_t type
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets/Clears the phy loop back mode, based on the enable value
|
||||
*/
|
||||
uint16_t
|
||||
PHY_set_loopback
|
||||
(
|
||||
uint8_t enable
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__MSS_ETHERNET_MAC_PHY_H*/
|
|
@ -0,0 +1,283 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion microcontroller subsystem GPIO bare metal driver implementation.
|
||||
*
|
||||
* SVN $Revision: 1753 $
|
||||
* SVN $Date: 2009-12-11 15:12:18 +0000 (Fri, 11 Dec 2009) $
|
||||
*/
|
||||
#include "mss_gpio.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL
|
||||
#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL
|
||||
|
||||
#define NB_OF_GPIO (uint32_t)32
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* Lookup table of GPIO configuration registers address indexed on GPIO ID.
|
||||
*/
|
||||
static uint32_t volatile * const g_config_reg_lut[NB_OF_GPIO] =
|
||||
{
|
||||
&(GPIO->GPIO_0_CFG),
|
||||
&(GPIO->GPIO_1_CFG),
|
||||
&(GPIO->GPIO_2_CFG),
|
||||
&(GPIO->GPIO_3_CFG),
|
||||
&(GPIO->GPIO_4_CFG),
|
||||
&(GPIO->GPIO_5_CFG),
|
||||
&(GPIO->GPIO_6_CFG),
|
||||
&(GPIO->GPIO_7_CFG),
|
||||
&(GPIO->GPIO_8_CFG),
|
||||
&(GPIO->GPIO_9_CFG),
|
||||
&(GPIO->GPIO_10_CFG),
|
||||
&(GPIO->GPIO_11_CFG),
|
||||
&(GPIO->GPIO_12_CFG),
|
||||
&(GPIO->GPIO_13_CFG),
|
||||
&(GPIO->GPIO_14_CFG),
|
||||
&(GPIO->GPIO_15_CFG),
|
||||
&(GPIO->GPIO_16_CFG),
|
||||
&(GPIO->GPIO_17_CFG),
|
||||
&(GPIO->GPIO_18_CFG),
|
||||
&(GPIO->GPIO_19_CFG),
|
||||
&(GPIO->GPIO_20_CFG),
|
||||
&(GPIO->GPIO_21_CFG),
|
||||
&(GPIO->GPIO_22_CFG),
|
||||
&(GPIO->GPIO_23_CFG),
|
||||
&(GPIO->GPIO_24_CFG),
|
||||
&(GPIO->GPIO_25_CFG),
|
||||
&(GPIO->GPIO_26_CFG),
|
||||
&(GPIO->GPIO_27_CFG),
|
||||
&(GPIO->GPIO_28_CFG),
|
||||
&(GPIO->GPIO_29_CFG),
|
||||
&(GPIO->GPIO_30_CFG),
|
||||
&(GPIO->GPIO_31_CFG)
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* Lookup table of Cortex-M3 GPIO interrupt number indexed on GPIO ID.
|
||||
*/
|
||||
static const IRQn_Type g_gpio_irqn_lut[NB_OF_GPIO] =
|
||||
{
|
||||
GPIO0_IRQn,
|
||||
GPIO1_IRQn,
|
||||
GPIO2_IRQn,
|
||||
GPIO3_IRQn,
|
||||
GPIO4_IRQn,
|
||||
GPIO5_IRQn,
|
||||
GPIO6_IRQn,
|
||||
GPIO7_IRQn,
|
||||
GPIO8_IRQn,
|
||||
GPIO9_IRQn,
|
||||
GPIO10_IRQn,
|
||||
GPIO11_IRQn,
|
||||
GPIO12_IRQn,
|
||||
GPIO13_IRQn,
|
||||
GPIO14_IRQn,
|
||||
GPIO15_IRQn,
|
||||
GPIO16_IRQn,
|
||||
GPIO17_IRQn,
|
||||
GPIO18_IRQn,
|
||||
GPIO19_IRQn,
|
||||
GPIO20_IRQn,
|
||||
GPIO21_IRQn,
|
||||
GPIO22_IRQn,
|
||||
GPIO23_IRQn,
|
||||
GPIO24_IRQn,
|
||||
GPIO25_IRQn,
|
||||
GPIO26_IRQn,
|
||||
GPIO27_IRQn,
|
||||
GPIO28_IRQn,
|
||||
GPIO29_IRQn,
|
||||
GPIO30_IRQn,
|
||||
GPIO31_IRQn
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* MSS_GPIO_init
|
||||
* See "mss_gpio.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_GPIO_init( void )
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
/* reset MSS GPIO hardware */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_GPIO_SOFTRESET_MASK;
|
||||
/* Clear any previously pended MSS GPIO interrupt */
|
||||
for ( i = 0U; i < NB_OF_GPIO; ++i )
|
||||
{
|
||||
NVIC_ClearPendingIRQ( g_gpio_irqn_lut[i] );
|
||||
}
|
||||
/* Take MSS GPIO hardware out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_GPIO_SOFTRESET_MASK;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* MSS_GPIO_config
|
||||
* See "mss_gpio.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_GPIO_config
|
||||
(
|
||||
mss_gpio_id_t port_id,
|
||||
uint32_t config
|
||||
)
|
||||
{
|
||||
uint32_t gpio_idx = (uint32_t)port_id;
|
||||
|
||||
ASSERT( gpio_idx < NB_OF_GPIO );
|
||||
|
||||
if ( gpio_idx < NB_OF_GPIO )
|
||||
{
|
||||
*(g_config_reg_lut[gpio_idx]) = config;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* MSS_GPIO_set_output
|
||||
* See "mss_gpio.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_GPIO_set_output
|
||||
(
|
||||
mss_gpio_id_t port_id,
|
||||
uint8_t value
|
||||
)
|
||||
{
|
||||
uint32_t gpio_idx = (uint32_t)port_id;
|
||||
|
||||
ASSERT( gpio_idx < NB_OF_GPIO );
|
||||
|
||||
if ( gpio_idx < NB_OF_GPIO )
|
||||
{
|
||||
GPIO_BITBAND->GPIO_OUT[gpio_idx] = (uint32_t)value;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* MSS_GPIO_drive_inout
|
||||
* See "mss_gpio.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_GPIO_drive_inout
|
||||
(
|
||||
mss_gpio_id_t port_id,
|
||||
mss_gpio_inout_state_t inout_state
|
||||
)
|
||||
{
|
||||
uint32_t outputs_state;
|
||||
uint32_t config;
|
||||
uint32_t gpio_idx = (uint32_t)port_id;
|
||||
|
||||
ASSERT( gpio_idx < NB_OF_GPIO );
|
||||
|
||||
if ( gpio_idx < NB_OF_GPIO )
|
||||
{
|
||||
switch( inout_state )
|
||||
{
|
||||
case MSS_GPIO_DRIVE_HIGH:
|
||||
/* Set output high */
|
||||
outputs_state = GPIO->GPIO_OUT;
|
||||
outputs_state |= (uint32_t)1 << gpio_idx;
|
||||
GPIO->GPIO_OUT = outputs_state;
|
||||
/* Enable output buffer */
|
||||
config = *(g_config_reg_lut[gpio_idx]);
|
||||
config |= OUTPUT_BUFFER_ENABLE_MASK;
|
||||
*(g_config_reg_lut[gpio_idx]) = config;
|
||||
break;
|
||||
|
||||
case MSS_GPIO_DRIVE_LOW:
|
||||
/* Set output low */
|
||||
outputs_state = GPIO->GPIO_OUT;
|
||||
outputs_state &= ~((uint32_t)((uint32_t)1 << gpio_idx));
|
||||
GPIO->GPIO_OUT = outputs_state;
|
||||
/* Enable output buffer */
|
||||
config = *(g_config_reg_lut[gpio_idx]);
|
||||
config |= OUTPUT_BUFFER_ENABLE_MASK;
|
||||
*(g_config_reg_lut[gpio_idx]) = config;
|
||||
break;
|
||||
|
||||
case MSS_GPIO_HIGH_Z:
|
||||
/* Disable output buffer */
|
||||
config = *(g_config_reg_lut[gpio_idx]);
|
||||
config &= ~OUTPUT_BUFFER_ENABLE_MASK;
|
||||
*(g_config_reg_lut[gpio_idx]) = config;
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* MSS_GPIO_enable_irq
|
||||
* See "mss_gpio.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_GPIO_enable_irq
|
||||
(
|
||||
mss_gpio_id_t port_id
|
||||
)
|
||||
{
|
||||
uint32_t cfg_value;
|
||||
uint32_t gpio_idx = (uint32_t)port_id;
|
||||
|
||||
ASSERT( gpio_idx < NB_OF_GPIO );
|
||||
|
||||
if ( gpio_idx < NB_OF_GPIO )
|
||||
{
|
||||
cfg_value = *(g_config_reg_lut[gpio_idx]);
|
||||
*(g_config_reg_lut[gpio_idx]) = (cfg_value | GPIO_INT_ENABLE_MASK);
|
||||
NVIC_EnableIRQ( g_gpio_irqn_lut[gpio_idx] );
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* MSS_GPIO_disable_irq
|
||||
* See "mss_gpio.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_GPIO_disable_irq
|
||||
(
|
||||
mss_gpio_id_t port_id
|
||||
)
|
||||
{
|
||||
uint32_t cfg_value;
|
||||
uint32_t gpio_idx = (uint32_t)port_id;
|
||||
|
||||
ASSERT( gpio_idx < NB_OF_GPIO );
|
||||
|
||||
if ( gpio_idx < NB_OF_GPIO )
|
||||
{
|
||||
cfg_value = *(g_config_reg_lut[gpio_idx]);
|
||||
*(g_config_reg_lut[gpio_idx]) = (cfg_value & ~GPIO_INT_ENABLE_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* MSS_GPIO_clear_irq
|
||||
* See "mss_gpio.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_GPIO_clear_irq
|
||||
(
|
||||
mss_gpio_id_t port_id
|
||||
)
|
||||
{
|
||||
uint32_t gpio_idx = (uint32_t)port_id;
|
||||
|
||||
ASSERT( gpio_idx < NB_OF_GPIO );
|
||||
|
||||
if ( gpio_idx < NB_OF_GPIO )
|
||||
{
|
||||
GPIO->GPIO_IRQ = ((uint32_t)1) << gpio_idx;
|
||||
NVIC_ClearPendingIRQ( g_gpio_irqn_lut[gpio_idx] );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,488 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion Microcontroller Subsystem GPIO bare metal software driver public
|
||||
* API.
|
||||
*
|
||||
* SVN $Revision: 1751 $
|
||||
* SVN $Date: 2009-12-11 15:05:48 +0000 (Fri, 11 Dec 2009) $
|
||||
*/
|
||||
|
||||
/*=========================================================================*//**
|
||||
@mainpage SmartFusion MSS GPIO Bare Metal Driver.
|
||||
|
||||
@section intro_sec Introduction
|
||||
The SmartFusion Microcontroller Subsystem (MSS) includes a block of 32 general
|
||||
purpose input/outputs (GPIO).
|
||||
This software driver provides a set of functions for controlling the MSS GPIO
|
||||
block as part of a bare metal system where no operating system is available.
|
||||
This driver can be adapted for use as part of an operating system but the
|
||||
implementation of the adaptation layer between this driver and the operating
|
||||
system's driver model is outside the scope of this driver.
|
||||
|
||||
@section hw_dependencies Hardware Flow Dependencies
|
||||
The configuration of all features of the MSS GPIOs is covered by this driver
|
||||
with the exception of the SmartFusion IOMUX configuration. SmartFusion allows
|
||||
multiple non-concurrent use of some external pins through IOMUX configuration.
|
||||
This feature allows optimizing external pin usage by assigning external pins
|
||||
for usage by either the microcontroller subsystem or the FPGA fabric.
|
||||
The MSS GPIO ports 0 to 15 are always connected to external pins but GPIO ports
|
||||
16 to 31 are routed through IOMUX to the SmartFusion device external pins.
|
||||
These IOMUX are configured using the MSS Configurator tool.
|
||||
Make sure the MSS GPIOs 16 to 31 are enabled in the MSS Configurator tool if
|
||||
you wish to use them
|
||||
|
||||
@section theory_op Theory of Operation
|
||||
The MSS GPIO driver uses the SmartFusion "Cortex Microcontroler Software
|
||||
Interface Standard - Peripheral Access Layer" (CMSIS-PAL) to access MSS hardware
|
||||
registers. You must ensure that the SmartFusion CMSIS-PAL is either included
|
||||
in the software toolchain used to build your project or is included in your
|
||||
project. The most up-to-date SmartFusion CMSIS-PAL files can be obtained using
|
||||
the Actel Firmware Catalog.
|
||||
|
||||
The MSS GPIO driver functions are grouped into the following categories:
|
||||
- Initiliazation
|
||||
- Configuration
|
||||
- Reading and setting GPIO state
|
||||
- Interrupt control
|
||||
|
||||
The MSS GPIO driver is initialized through a call to the GPIO_init() function.
|
||||
The GPIO_init() function must be called before any other GPIO driver functions
|
||||
can be called.
|
||||
|
||||
Each GPIO port is individually configured through a call to the
|
||||
MSS_GPIO_config() function. Configuration includes deciding if a GPIO port
|
||||
will be used as an input, an output or both. GPIO ports configured as inputs can be
|
||||
further configured to generate interrupts based on the input's state.
|
||||
Interrupts can be level or edge sensitive.
|
||||
|
||||
The state of the GPIO ports can be read and set using the following functions:
|
||||
- MSS_GPIO_get_inputs()
|
||||
- MSS_GPIO_get_outputs()
|
||||
- MSS_GPIO_set_outputs()
|
||||
- MSS_GPIO_set_output()
|
||||
- MSS_GPIO_drive_inout()
|
||||
|
||||
Interrupts generated by GPIO ports configured as inputs are controlled using
|
||||
the following functions:
|
||||
- MSS_GPIO_enable_irq()
|
||||
- MSS_GPIO_disable_irq()
|
||||
- MSS_GPIO_clear_irq()
|
||||
|
||||
*//*=========================================================================*/
|
||||
#ifndef MSS_GPIO_H_
|
||||
#define MSS_GPIO_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The mss_gpio_id_t enumeration is used to identify GPIOs as part of the
|
||||
parameter to functions:
|
||||
- MSS_GPIO_config(),
|
||||
- MSS_GPIO_drive_inout(),
|
||||
- MSS_GPIO_enable_irq(),
|
||||
- MSS_GPIO_disable_irq(),
|
||||
- MSS_GPIO_clear_irq()
|
||||
*/
|
||||
typedef enum __mss_gpio_id_t
|
||||
{
|
||||
MSS_GPIO_0 = 0,
|
||||
MSS_GPIO_1 = 1,
|
||||
MSS_GPIO_2 = 2,
|
||||
MSS_GPIO_3 = 3,
|
||||
MSS_GPIO_4 = 4,
|
||||
MSS_GPIO_5 = 5,
|
||||
MSS_GPIO_6 = 6,
|
||||
MSS_GPIO_7 = 7,
|
||||
MSS_GPIO_8 = 8,
|
||||
MSS_GPIO_9 = 9,
|
||||
MSS_GPIO_10 = 10,
|
||||
MSS_GPIO_11 = 11,
|
||||
MSS_GPIO_12 = 12,
|
||||
MSS_GPIO_13 = 13,
|
||||
MSS_GPIO_14 = 14,
|
||||
MSS_GPIO_15 = 15,
|
||||
MSS_GPIO_16 = 16,
|
||||
MSS_GPIO_17 = 17,
|
||||
MSS_GPIO_18 = 18,
|
||||
MSS_GPIO_19 = 19,
|
||||
MSS_GPIO_20 = 20,
|
||||
MSS_GPIO_21 = 21,
|
||||
MSS_GPIO_22 = 22,
|
||||
MSS_GPIO_23 = 23,
|
||||
MSS_GPIO_24 = 24,
|
||||
MSS_GPIO_25 = 25,
|
||||
MSS_GPIO_26 = 26,
|
||||
MSS_GPIO_27 = 27,
|
||||
MSS_GPIO_28 = 28,
|
||||
MSS_GPIO_29 = 29,
|
||||
MSS_GPIO_30 = 30,
|
||||
MSS_GPIO_31 = 31
|
||||
} mss_gpio_id_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
GPIO ports definitions used to identify GPIOs as part of the parameter to
|
||||
function MSS_GPIO_set_outputs().
|
||||
These definitions can also be used to identity GPIO through logical
|
||||
operations on the return value of function MSS_GPIO_get_inputs().
|
||||
*/
|
||||
#define MSS_GPIO_0_MASK 0x00000001UL
|
||||
#define MSS_GPIO_1_MASK 0x00000002UL
|
||||
#define MSS_GPIO_2_MASK 0x00000004UL
|
||||
#define MSS_GPIO_3_MASK 0x00000008UL
|
||||
#define MSS_GPIO_4_MASK 0x00000010UL
|
||||
#define MSS_GPIO_5_MASK 0x00000020UL
|
||||
#define MSS_GPIO_6_MASK 0x00000040UL
|
||||
#define MSS_GPIO_7_MASK 0x00000080UL
|
||||
#define MSS_GPIO_8_MASK 0x00000100UL
|
||||
#define MSS_GPIO_9_MASK 0x00000200UL
|
||||
#define MSS_GPIO_10_MASK 0x00000400UL
|
||||
#define MSS_GPIO_11_MASK 0x00000800UL
|
||||
#define MSS_GPIO_12_MASK 0x00001000UL
|
||||
#define MSS_GPIO_13_MASK 0x00002000UL
|
||||
#define MSS_GPIO_14_MASK 0x00004000UL
|
||||
#define MSS_GPIO_15_MASK 0x00008000UL
|
||||
#define MSS_GPIO_16_MASK 0x00010000UL
|
||||
#define MSS_GPIO_17_MASK 0x00020000UL
|
||||
#define MSS_GPIO_18_MASK 0x00040000UL
|
||||
#define MSS_GPIO_19_MASK 0x00080000UL
|
||||
#define MSS_GPIO_20_MASK 0x00100000UL
|
||||
#define MSS_GPIO_21_MASK 0x00200000UL
|
||||
#define MSS_GPIO_22_MASK 0x00400000UL
|
||||
#define MSS_GPIO_23_MASK 0x00800000UL
|
||||
#define MSS_GPIO_24_MASK 0x01000000UL
|
||||
#define MSS_GPIO_25_MASK 0x02000000UL
|
||||
#define MSS_GPIO_26_MASK 0x04000000UL
|
||||
#define MSS_GPIO_27_MASK 0x08000000UL
|
||||
#define MSS_GPIO_28_MASK 0x10000000UL
|
||||
#define MSS_GPIO_29_MASK 0x20000000UL
|
||||
#define MSS_GPIO_30_MASK 0x40000000UL
|
||||
#define MSS_GPIO_31_MASK 0x80000000UL
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* GPIO modes
|
||||
*/
|
||||
#define MSS_GPIO_INPUT_MODE 0x0000000002UL
|
||||
#define MSS_GPIO_OUTPUT_MODE 0x0000000005UL
|
||||
#define MSS_GPIO_INOUT_MODE 0x0000000003UL
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* Possible GPIO inputs interrupt configurations.
|
||||
*/
|
||||
#define MSS_GPIO_IRQ_LEVEL_HIGH 0x0000000000UL
|
||||
#define MSS_GPIO_IRQ_LEVEL_LOW 0x0000000020UL
|
||||
#define MSS_GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL
|
||||
#define MSS_GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL
|
||||
#define MSS_GPIO_IRQ_EDGE_BOTH 0x0000000080UL
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* Possible states for GPIO configured as INOUT.
|
||||
*/
|
||||
typedef enum mss_gpio_inout_state
|
||||
{
|
||||
MSS_GPIO_DRIVE_LOW = 0,
|
||||
MSS_GPIO_DRIVE_HIGH,
|
||||
MSS_GPIO_HIGH_Z
|
||||
} mss_gpio_inout_state_t;
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_init() function initializes the SmartFusion MSS GPIO block. It
|
||||
resets the MSS GPIO hardware block and it also clears any pending MSS GPIO
|
||||
interrupts in the Cortex-M3 interrupt controller.
|
||||
|
||||
@return
|
||||
none.
|
||||
*/
|
||||
void MSS_GPIO_init( void );
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_config() function is used to configure an individual
|
||||
GPIO port.
|
||||
|
||||
@param port_id
|
||||
The port_id parameter identifies the GPIO port to be configured.
|
||||
An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
|
||||
port is used to identify the GPIO port. For example MSS_GPIO_0 identifies
|
||||
the first GPIO port and MSS_GPIO_31 the last one.
|
||||
|
||||
@param config
|
||||
The config parameter specifies the configuration to be applied to the GPIO
|
||||
port identified by the port_id parameter. It is a logical OR of the required
|
||||
I/O mode and the required interrupt mode. The interrupt mode is not relevant
|
||||
if the GPIO is configured as an output only.
|
||||
These I/O mode constants are allowed:
|
||||
- MSS_GPIO_INPUT_MODE
|
||||
- MSS_GPIO_OUTPUT_MODE
|
||||
- MSS_GPIO_INOUT_MODE
|
||||
These interrupt mode constants are allowed:
|
||||
- MSS_GPIO_IRQ_LEVEL_HIGH
|
||||
- MSS_GPIO_IRQ_LEVEL_LOW
|
||||
- MSS_GPIO_IRQ_EDGE_POSITIVE
|
||||
- MSS_GPIO_IRQ_EDGE_NEGATIVE
|
||||
- MSS_GPIO_IRQ_EDGE_BOTH
|
||||
|
||||
@return
|
||||
none.
|
||||
|
||||
Example:
|
||||
The following call will configure GPIO 4 as an input generating interrupts on
|
||||
a low to high transition of the input:
|
||||
@code
|
||||
MSS_GPIO_config( MSS_GPIO_4, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE );
|
||||
@endcode
|
||||
*/
|
||||
void MSS_GPIO_config
|
||||
(
|
||||
mss_gpio_id_t port_id,
|
||||
uint32_t config
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_set_outputs() function is used to set the state of all GPIO
|
||||
ports configured as outputs.
|
||||
|
||||
@param value
|
||||
The value parameter specifies the state of the GPIO ports configured as
|
||||
outputs. It is a bit mask of the form (MSS_GPIO_n_MASK | MSS_GPIO_m_MASK) where n
|
||||
and m are numbers identifying GPIOs.
|
||||
For example (MSS_GPIO_0_MASK | MSS_GPIO_1_MASK | MSS_GPIO_2_MASK ) specifies
|
||||
that the first, second and third GPIOs' must be set high and all other
|
||||
outputs set low.
|
||||
The driver provides 32 mask constants, MSS_GPIO_0_MASK to MSS_GPIO_31_MASK
|
||||
inclusive, for this purpose.
|
||||
|
||||
@return
|
||||
none.
|
||||
|
||||
Example 1:
|
||||
Set GPIOs outputs 0 and 8 high and all other GPIO outputs low.
|
||||
@code
|
||||
MSS_GPIO_set_outputs( MSS_GPIO_0_MASK | MSS_GPIO_8_MASK );
|
||||
@endcode
|
||||
|
||||
Example 2:
|
||||
Set GPIOs outputs 2 and 4 low without affecting other GPIO outputs.
|
||||
@code
|
||||
uint32_t gpio_outputs;
|
||||
gpio_outputs = MSS_GPIO_get_outputs();
|
||||
gpio_outputs &= ~( MSS_GPIO_2_MASK | MSS_GPIO_4_MASK );
|
||||
MSS_GPIO_set_outputs( gpio_outputs );
|
||||
@endcode
|
||||
|
||||
@see MSS_GPIO_get_outputs()
|
||||
*/
|
||||
static __INLINE void
|
||||
MSS_GPIO_set_outputs
|
||||
(
|
||||
uint32_t value
|
||||
)
|
||||
{
|
||||
GPIO->GPIO_OUT = value;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_set_output() function is used to set the state of a single GPIO
|
||||
port configured as output.
|
||||
|
||||
@param port_id
|
||||
The port_id parameter identifies the GPIO port that is to have its output set.
|
||||
An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
|
||||
port is used to identify the GPIO port. For example MSS_GPIO_0 identifies the
|
||||
first GPIO port and MSS_GPIO_31 the last one.
|
||||
|
||||
@param value
|
||||
The value parameter specifies the desired state for the GPIO output. A value
|
||||
of 0 will set the output low and a value of 1 will set the output high.
|
||||
|
||||
@return
|
||||
none.
|
||||
*/
|
||||
void MSS_GPIO_set_output
|
||||
(
|
||||
mss_gpio_id_t port_id,
|
||||
uint8_t value
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_get_inputs() function is used to read the current state of all
|
||||
GPIO ports confgured as inputs.
|
||||
|
||||
@return
|
||||
This function returns a 32 bit unsigned integer where each bit represents
|
||||
the state of a GPIO input. The least significant bit represents the state of
|
||||
GPIO input 0 and the most significant bit the state of GPIO input 31.
|
||||
|
||||
Example:
|
||||
Read and assign the current state of the GPIO outputs to a variable.
|
||||
@code
|
||||
uint32_t gpio_inputs;
|
||||
gpio_inputs = MSS_GPIO_get_inputs();
|
||||
@endcode
|
||||
*/
|
||||
static __INLINE uint32_t
|
||||
MSS_GPIO_get_inputs( void )
|
||||
{
|
||||
return GPIO->GPIO_IN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_get_outputs() function is used to read the current state of all
|
||||
GPIO ports confgured as outputs.
|
||||
|
||||
@return
|
||||
This function returns a 32 bit unsigned integer where each bit represents
|
||||
the state of a GPIO output. The least significant bit represents the state
|
||||
of GPIO output 0 and the most significant bit the state of GPIO output 31.
|
||||
|
||||
Example:
|
||||
Read and assign the current state of the GPIO outputs to a variable.
|
||||
@code
|
||||
uint32_t gpio_outputs;
|
||||
gpio_outputs = MSS_GPIO_get_outputs();
|
||||
@endcode
|
||||
*/
|
||||
static __INLINE uint32_t
|
||||
MSS_GPIO_get_outputs( void )
|
||||
{
|
||||
return GPIO->GPIO_OUT;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_drive_inout() function is used to set the output state of a single
|
||||
GPIO port configured as an INOUT. An INOUT GPIO can be in one of three states:
|
||||
- high
|
||||
- low
|
||||
- high impedance
|
||||
An INOUT output would typically be used where several devices can drive the
|
||||
state of a shared signal line. The high and low states are equivalent to the
|
||||
high and low states of a GPIO configured as output. The high impedance state
|
||||
is used to prevent the GPIO from driving its output state onto the signal line,
|
||||
while at the same time allowing the input state of the GPIO to be read
|
||||
|
||||
@param port_id
|
||||
The port_id parameter identifies the GPIO port for which you want to change
|
||||
the output state.
|
||||
An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
|
||||
port is used to identify the GPIO port. For example MSS_GPIO_0 identifies
|
||||
the first GPIO port and MSS_GPIO_31 the last one.
|
||||
|
||||
@param inout_state
|
||||
The inout_state parameter specifies the state of the GPIO port identified by
|
||||
the port_id parameter. Allowed values of type mss_gpio_inout_state_t are:
|
||||
- MSS_GPIO_DRIVE_HIGH
|
||||
- MSS_GPIO_DRIVE_LOW
|
||||
- MSS_GPIO_HIGH_Z (high impedance)
|
||||
|
||||
@return
|
||||
none.
|
||||
|
||||
Example:
|
||||
The call to MSS_GPIO_drive_inout() below will set the GPIO 7 output to the
|
||||
high impedance state.
|
||||
@code
|
||||
MSS_GPIO_drive_inout( MSS_GPIO_7, MSS_GPIO_HIGH_Z );
|
||||
@endcode
|
||||
*/
|
||||
void MSS_GPIO_drive_inout
|
||||
(
|
||||
mss_gpio_id_t port_id,
|
||||
mss_gpio_inout_state_t inout_state
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_enable_irq() function is used to enable interrupt generation
|
||||
for the specified GPIO input. Interrupts are generated based on the state of
|
||||
the GPIO input and the interrupt mode configured for it by MSS_GPIO_config().
|
||||
|
||||
@param port_id
|
||||
The port_id parameter identifies the GPIO port for which you want to enable
|
||||
interrupt generation.
|
||||
An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
|
||||
port is used to identify the GPIO port. For example MSS_GPIO_0 identifies the
|
||||
first GPIO port and MSS_GPIO_31 the last one.
|
||||
|
||||
@return
|
||||
none.
|
||||
|
||||
Example:
|
||||
The call to MSS_GPIO_enable_irq() below will allow GPIO 8 to generate
|
||||
interrupts.
|
||||
@code
|
||||
MSS_GPIO_enable_irq( MSS_GPIO_8 );
|
||||
@endcode
|
||||
*/
|
||||
void MSS_GPIO_enable_irq
|
||||
(
|
||||
mss_gpio_id_t port_id
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_disable_irq() function is used to disable interrupt generation
|
||||
for the specified GPIO input.
|
||||
|
||||
@param port_id
|
||||
The port_id parameter identifies the GPIO port for which you want to disable
|
||||
interrupt generation.
|
||||
An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
|
||||
port is used to identify the GPIO port. For example MSS_GPIO_0 identifies the
|
||||
first GPIO port and MSS_GPIO_31 the last one.
|
||||
|
||||
@return
|
||||
none.
|
||||
|
||||
Example:
|
||||
The call to MSS_GPIO_disable_irq() below will prevent GPIO 8 from generating
|
||||
interrupts.
|
||||
@code
|
||||
MSS_GPIO_disable_irq( MSS_GPIO_8 );
|
||||
@endcode
|
||||
*/
|
||||
void MSS_GPIO_disable_irq
|
||||
(
|
||||
mss_gpio_id_t port_id
|
||||
);
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
The MSS_GPIO_clear_irq() function is used to clear a pending interrupt from
|
||||
the specified GPIO input.
|
||||
Note: The MSS_GPIO_clear_irq() function must be called as part of any GPIO
|
||||
interrupt service routine (ISR) in order to prevent the same interrupt event
|
||||
retriggering a call to the GPIO ISR. The function also clears the interrupt
|
||||
in the Cortex-M3 interrupt controller through a call to NVIC_ClearPendingIRQ().
|
||||
|
||||
@param port_id
|
||||
The port_id parameter identifies the GPIO input for which you want to clear the
|
||||
interrupt.
|
||||
An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
|
||||
port is used to identify the GPIO port. For example MSS_GPIO_0 identifies the
|
||||
first GPIO port and MSS_GPIO_31 the last one.
|
||||
|
||||
@return
|
||||
none.
|
||||
|
||||
Example:
|
||||
The example below demonstrates the use of the MSS_GPIO_clear_irq() function
|
||||
as part of the GPIO 9 interrupt service routine.
|
||||
@code
|
||||
void GPIO9_IRQHandler( void )
|
||||
{
|
||||
do_interrupt_processing();
|
||||
|
||||
MSS_GPIO_clear_irq( MSS_GPIO_9 );
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
void MSS_GPIO_clear_irq
|
||||
(
|
||||
mss_gpio_id_t port_id
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MSS_GPIO_H_ */
|
|
@ -0,0 +1,413 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion microcontroller subsystem Peripheral DMA bare metal software
|
||||
* driver implementation.
|
||||
*
|
||||
* SVN $Revision: 2110 $
|
||||
* SVN $Date: 2010-02-05 15:24:19 +0000 (Fri, 05 Feb 2010) $
|
||||
*/
|
||||
#include "mss_pdma.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void DMA_IRQHandler( void );
|
||||
#else
|
||||
void DMA_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
Offset of the posted writes WRITE_ADJ bits in a PDMA channel's configuration
|
||||
register.
|
||||
*/
|
||||
#define CHANNEL_N_POSTED_WRITE_ADJUST_SHIFT 14
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
* Look-up table use to derice a channel's control register value from the
|
||||
* requested source/destination. This table is incexed on the pdma_src_dest_t
|
||||
* enumeration.
|
||||
*/
|
||||
#define CHANNEL_N_CTRL_PDMA_MASK (uint32_t)0x00000001
|
||||
#define CHANNEL_N_PERIPH_SELECT_SHIFT (uint32_t)23
|
||||
#define CHANNEL_N_DIRECTION_MASK (uint32_t)0x00000002
|
||||
|
||||
const uint32_t src_dest_to_ctrl_reg_lut[] =
|
||||
{
|
||||
CHANNEL_N_CTRL_PDMA_MASK, /* PDMA_FROM_UART_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)1 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_UART_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)2 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_UART_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)3 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_UART_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)4 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_SPI_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)5 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_SPI_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)6 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_SPI_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)7 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_SPI_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)8 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_FPGA_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)8 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_FPGA_1 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)9 << CHANNEL_N_PERIPH_SELECT_SHIFT), /* PDMA_FROM_FPGA_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)9 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_FPGA_0 */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)10 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_ACE */
|
||||
CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)11 << CHANNEL_N_PERIPH_SELECT_SHIFT) /* PDMA_FROM_ACE */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
#define PDMA_MASTER_ENABLE (uint32_t)0x04
|
||||
#define PDMA_SOFT_RESET (uint32_t)0x20
|
||||
|
||||
/*-------------------------------------------------------------------------*//**
|
||||
*
|
||||
*/
|
||||
#define NB_OF_PDMA_CHANNELS 8
|
||||
|
||||
#define NEXT_CHANNEL_A 0U
|
||||
#define NEXT_CHANNEL_B 1U
|
||||
|
||||
#define CHANNEL_STOPPED 0U
|
||||
#define CHANNEL_STARTED 1U
|
||||
|
||||
static uint8_t g_pdma_next_channel[NB_OF_PDMA_CHANNELS];
|
||||
static uint8_t g_pdma_started_a[NB_OF_PDMA_CHANNELS];
|
||||
static uint8_t g_pdma_started_b[NB_OF_PDMA_CHANNELS];
|
||||
static pdma_channel_isr_t g_pdma_isr_table[NB_OF_PDMA_CHANNELS];
|
||||
static const uint16_t g_pdma_status_mask[NB_OF_PDMA_CHANNELS] =
|
||||
{
|
||||
(uint16_t)0x0003, /* PDMA_CHANNEL_0 */
|
||||
(uint16_t)0x000C, /* PDMA_CHANNEL_1 */
|
||||
(uint16_t)0x0030, /* PDMA_CHANNEL_2 */
|
||||
(uint16_t)0x00C0, /* PDMA_CHANNEL_3 */
|
||||
(uint16_t)0x0300, /* PDMA_CHANNEL_4 */
|
||||
(uint16_t)0x0C00, /* PDMA_CHANNEL_5 */
|
||||
(uint16_t)0x3000, /* PDMA_CHANNEL_6 */
|
||||
(uint16_t)0xC000, /* PDMA_CHANNEL_7 */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_init( void )
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
/* Enable PDMA master access to comms matrix. */
|
||||
SYSREG->AHB_MATRIX_CR |= PDMA_MASTER_ENABLE;
|
||||
|
||||
/* Reset PDMA block. */
|
||||
SYSREG->SOFT_RST_CR |= PDMA_SOFT_RESET;
|
||||
|
||||
/* Clear any previously pended MSS PDMA interrupt */
|
||||
NVIC_ClearPendingIRQ( DMA_IRQn );
|
||||
|
||||
/* Take PDMA controller out of reset*/
|
||||
SYSREG->SOFT_RST_CR &= ~PDMA_SOFT_RESET;
|
||||
|
||||
/* Initialize channels state information. */
|
||||
for ( i = 0; i < NB_OF_PDMA_CHANNELS; ++i )
|
||||
{
|
||||
g_pdma_next_channel[i] = NEXT_CHANNEL_A;
|
||||
g_pdma_started_a[i] = CHANNEL_STOPPED;
|
||||
g_pdma_started_b[i] = CHANNEL_STOPPED;
|
||||
g_pdma_isr_table[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
#define CHANNEL_RESET_MASK (uint32_t)0x00000020
|
||||
|
||||
void PDMA_configure
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
pdma_src_dest_t src_dest,
|
||||
uint32_t channel_cfg,
|
||||
uint8_t write_adjust
|
||||
)
|
||||
{
|
||||
/* Reset the channel. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CHANNEL_RESET_MASK;
|
||||
PDMA->CHANNEL[channel_id].CRTL &= ~CHANNEL_RESET_MASK;
|
||||
|
||||
/* Configure PDMA channel's data source and destination. */
|
||||
if ( src_dest != PDMA_MEM_TO_MEM )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= src_dest_to_ctrl_reg_lut[src_dest];
|
||||
}
|
||||
|
||||
/* Configure PDMA channel trnasfer size, priority, source and destination address increment. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= channel_cfg;
|
||||
|
||||
/* Posted write adjust. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= ((uint32_t)write_adjust << CHANNEL_N_POSTED_WRITE_ADJUST_SHIFT);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
#define PAUSE_MASK (uint32_t)0x00000010
|
||||
|
||||
#define BUFFER_B_SELECT_MASK (uint32_t)0x00000004
|
||||
|
||||
#define CLEAR_PORT_A_DONE_MASK (uint32_t)0x00000080
|
||||
#define CLEAR_PORT_B_DONE_MASK (uint32_t)0x00000100
|
||||
|
||||
#define PORT_A_COMPLETE_MASK (uint32_t)0x00000001
|
||||
#define PORT_B_COMPLETE_MASK (uint32_t)0x00000002
|
||||
|
||||
void PDMA_start
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
uint32_t src_addr,
|
||||
uint32_t dest_addr,
|
||||
uint16_t transfer_count
|
||||
)
|
||||
{
|
||||
/* Pause transfer. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= PAUSE_MASK;
|
||||
|
||||
/* Clear complete transfers. */
|
||||
if ( PDMA->CHANNEL[channel_id].STATUS & PORT_A_COMPLETE_MASK )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_A_DONE_MASK;
|
||||
g_pdma_started_a[channel_id] = CHANNEL_STOPPED;
|
||||
}
|
||||
if ( PDMA->CHANNEL[channel_id].STATUS & PORT_B_COMPLETE_MASK )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_B_DONE_MASK;
|
||||
g_pdma_started_b[channel_id] = CHANNEL_STOPPED;
|
||||
}
|
||||
|
||||
/* Load source, destination and transfer count. */
|
||||
if ( PDMA->CHANNEL[channel_id].STATUS & BUFFER_B_SELECT_MASK )
|
||||
{
|
||||
g_pdma_next_channel[channel_id] = NEXT_CHANNEL_A;
|
||||
g_pdma_started_b[channel_id] = CHANNEL_STARTED;
|
||||
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_SRC_ADDR = src_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_DEST_ADDR = dest_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_TRANSFER_COUNT = transfer_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pdma_next_channel[channel_id] = NEXT_CHANNEL_B;
|
||||
g_pdma_started_a[channel_id] = CHANNEL_STARTED;
|
||||
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_SRC_ADDR = src_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_DEST_ADDR = dest_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_TRANSFER_COUNT = transfer_count;
|
||||
}
|
||||
|
||||
/* Start transfer */
|
||||
PDMA->CHANNEL[channel_id].CRTL &= ~PAUSE_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_load_next_buffer
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
uint32_t src_addr,
|
||||
uint32_t dest_addr,
|
||||
uint16_t transfer_count
|
||||
)
|
||||
{
|
||||
if ( NEXT_CHANNEL_A == g_pdma_next_channel[channel_id] )
|
||||
{
|
||||
/* Wait for channel A current transfer completion. */
|
||||
if ( CHANNEL_STARTED == g_pdma_started_a[channel_id] )
|
||||
{
|
||||
uint32_t completed;
|
||||
uint32_t channel_mask;
|
||||
channel_mask = (uint32_t)1 << ((uint32_t)channel_id * 2U);
|
||||
do {
|
||||
completed = PDMA->BUFFER_STATUS & channel_mask;
|
||||
} while( !completed );
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_A_DONE_MASK;
|
||||
}
|
||||
/* Load source, destination and transfer count. */
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_SRC_ADDR = src_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_DEST_ADDR = dest_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_A_TRANSFER_COUNT = transfer_count;
|
||||
|
||||
/* Update channel state information. */
|
||||
g_pdma_next_channel[channel_id] = NEXT_CHANNEL_B;
|
||||
g_pdma_started_a[channel_id] = CHANNEL_STARTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for channel B current transfer completion. */
|
||||
if ( CHANNEL_STARTED == g_pdma_started_b[channel_id] )
|
||||
{
|
||||
uint32_t completed;
|
||||
uint32_t channel_mask;
|
||||
channel_mask = (uint32_t)1 << (((uint32_t)channel_id * 2U) + 1U);
|
||||
do {
|
||||
completed = PDMA->BUFFER_STATUS & channel_mask;
|
||||
} while( !completed );
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_B_DONE_MASK;
|
||||
}
|
||||
/* Load source, destination and transfer count. */
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_SRC_ADDR = src_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_DEST_ADDR = dest_addr;
|
||||
PDMA->CHANNEL[channel_id].BUFFER_B_TRANSFER_COUNT = transfer_count;
|
||||
|
||||
/* Update channel state information. */
|
||||
g_pdma_next_channel[channel_id] = NEXT_CHANNEL_A;
|
||||
g_pdma_started_b[channel_id] = CHANNEL_STARTED;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
uint32_t PDMA_status
|
||||
(
|
||||
pdma_channel_id_t channel_id
|
||||
)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
status = PDMA->CHANNEL[channel_id].STATUS & (PORT_A_COMPLETE_MASK | PORT_B_COMPLETE_MASK);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
*
|
||||
*/
|
||||
#define CHANNEL_0_STATUS_BITS_MASK (uint16_t)0x0003
|
||||
#define CHANNEL_1_STATUS_BITS_MASK (uint16_t)0x000C
|
||||
#define CHANNEL_2_STATUS_BITS_MASK (uint16_t)0x0030
|
||||
#define CHANNEL_3_STATUS_BITS_MASK (uint16_t)0x00C0
|
||||
#define CHANNEL_4_STATUS_BITS_MASK (uint16_t)0x0300
|
||||
#define CHANNEL_5_STATUS_BITS_MASK (uint16_t)0x0C00
|
||||
#define CHANNEL_6_STATUS_BITS_MASK (uint16_t)0x3000
|
||||
#define CHANNEL_7_STATUS_BITS_MASK (uint16_t)0xC000
|
||||
|
||||
static pdma_channel_id_t get_channel_id_from_status
|
||||
(
|
||||
uint16_t status
|
||||
)
|
||||
{
|
||||
pdma_channel_id_t channel_id = PDMA_CHANNEL_0;
|
||||
|
||||
if ( status & CHANNEL_0_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_0;
|
||||
}
|
||||
else if ( status & CHANNEL_1_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_1;
|
||||
}
|
||||
else if ( status & CHANNEL_2_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_2;
|
||||
}
|
||||
else if ( status & CHANNEL_3_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_3;
|
||||
}
|
||||
else if ( status & CHANNEL_4_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_4;
|
||||
}
|
||||
else if ( status & CHANNEL_5_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_5;
|
||||
}
|
||||
else if ( status & CHANNEL_6_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_6;
|
||||
}
|
||||
else if ( status & CHANNEL_7_STATUS_BITS_MASK )
|
||||
{
|
||||
channel_id = PDMA_CHANNEL_7;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
return channel_id;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
*
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void DMA_IRQHandler( void )
|
||||
#else
|
||||
void DMA_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
uint16_t status;
|
||||
pdma_channel_id_t channel_id;
|
||||
|
||||
status = (uint16_t)PDMA->BUFFER_STATUS;
|
||||
|
||||
do {
|
||||
channel_id = get_channel_id_from_status( status );
|
||||
status &= (uint16_t)~g_pdma_status_mask[channel_id];
|
||||
if ( 0 != g_pdma_isr_table[channel_id])
|
||||
{
|
||||
g_pdma_isr_table[channel_id]();
|
||||
}
|
||||
} while ( 0U != status );
|
||||
|
||||
NVIC_ClearPendingIRQ( DMA_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_set_irq_handler
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
pdma_channel_isr_t handler
|
||||
)
|
||||
{
|
||||
/* Save address of handler function in PDMA driver ISR lookup table. */
|
||||
g_pdma_isr_table[channel_id] = handler;
|
||||
|
||||
/* Enable PDMA channel's interrupt. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= PDMA_IRQ_ENABLE_MASK;
|
||||
|
||||
/* Enable PDMA interrupt in Cortex-M3 NVIC. */
|
||||
NVIC_EnableIRQ( DMA_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_enable_irq( pdma_channel_id_t channel_id )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= PDMA_IRQ_ENABLE_MASK;
|
||||
NVIC_EnableIRQ( DMA_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_pdma.h for description of this function.
|
||||
*/
|
||||
void PDMA_clear_irq
|
||||
(
|
||||
pdma_channel_id_t channel_id
|
||||
)
|
||||
{
|
||||
/* Clear interrupt in PDMA controller. */
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_A_DONE_MASK;
|
||||
PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_B_DONE_MASK;
|
||||
|
||||
/* Clear interrupt in Cortex-M3 NVIC. */
|
||||
NVIC_ClearPendingIRQ( DMA_IRQn );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,703 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion microcontroller subsystem Peripheral DMA bare metal software
|
||||
* driver public API.
|
||||
*
|
||||
* SVN $Revision: 2110 $
|
||||
* SVN $Date: 2010-02-05 15:24:19 +0000 (Fri, 05 Feb 2010) $
|
||||
*/
|
||||
/*=========================================================================*//**
|
||||
@mainpage SmartFusion MSS GPIO Bare Metal Driver.
|
||||
|
||||
@section intro_sec Introduction
|
||||
The SmartFusion Microcontroller Subsystem (MSS) includes an 8 channel
|
||||
Peripheral DMA (PDMA) controller.
|
||||
This software driver provides a set of functions for controlling the MSS PDMA
|
||||
controller as part of a bare metal system where no operating system is available.
|
||||
This driver can be adapted for use as part of an operating system but the
|
||||
implementation of the adaptation layer between this driver and the operating
|
||||
system's driver model is outside the scope of this driver.
|
||||
|
||||
@section theory_op Theory of Operation
|
||||
The MSS PDMA driver uses the SmartFusion "Cortex Microcontroler Software
|
||||
Interface Standard - Peripheral Access Layer" (CMSIS-PAL) to access MSS hardware
|
||||
registers. You must ensure that the SmartFusion CMSIS-PAL is either included
|
||||
in the software toolchain used to build your project or is included in your
|
||||
project. The most up-to-date SmartFusion CMSIS-PAL files can be obtained using
|
||||
the Actel Firmware Catalog.
|
||||
|
||||
The MSS PDMA driver functions are grouped into the following categories:
|
||||
- Initialization
|
||||
- Configuration
|
||||
- DMA transfer control
|
||||
- Interrupt control
|
||||
|
||||
The MSS PDMA driver is initialized through a call to the PDMA_init() function.
|
||||
The PDMA_init() function must be called before any other PDMA driver functions
|
||||
can be called.
|
||||
|
||||
Each PDMA channel is individually configured through a call to the PDMA_configure()
|
||||
function. Configuration includes:
|
||||
- channel priority
|
||||
- transfer size
|
||||
- source and/or destination address increment
|
||||
- source or destination of the DMA transfer
|
||||
PDMA channels can be divided into high and low priority channels. High priority
|
||||
channels are given more opportunities to perform transfers than low priority
|
||||
channels when there are continuous high priority channels requests. The ratio
|
||||
of high priority to low priority PDMA transfers is configurable through the
|
||||
PDMA_set_priority() function.
|
||||
PDMA channels can be configured to perform byte (8 bits), half-word (16 bits)
|
||||
or word (32 bits) transfers.
|
||||
The source and destination address of a PDMA channel’s transfers can be
|
||||
independently configured to increment by 0, 1, 2 or 4 bytes. For example, the
|
||||
content of a byte buffer located in RAM can be transferred into a peripheral’s
|
||||
transmit register by configuring the source address increment to one byte and
|
||||
no increment of the destination address.
|
||||
The source or destination of a PDMA channel’s transfers can be configured to
|
||||
be one of the MSS peripherals. This allows the PDMA controller to use some
|
||||
hardware flow control signaling with the peripheral to avoid overrunning the
|
||||
peripheral’s data buffer when the peripheral is the destination of the DMA
|
||||
transfer, or attempting to read data from the peripheral while it is not ready
|
||||
when the peripheral is the source of the transfer.
|
||||
A PDMA channel can also be configured to transfer data between two memory
|
||||
mapped locations (memory to memory). No hardware flow control is used by the
|
||||
PDMA controller for data transfer in this configuration.
|
||||
|
||||
A DMA transfer can be initiated by a call to the PDMA_start() function after a
|
||||
PDMA channel has been configured. Once started, further data can be pushed
|
||||
through the PDMA channel by calling the PDMA_load_next_buffer() function. The
|
||||
PDMA_load_next_buffer() function can be called every time a call to the
|
||||
PDMA_status() function indicates that the PDMA channel used for the transfer
|
||||
has a free buffer or it can be called as a result of a PDMA interrupt.
|
||||
|
||||
A DMA transfer can be paused and resumed through calls to functions PDMA_pause()
|
||||
and PDMA_resume().
|
||||
|
||||
Your application can manage DMA transfers using interrupts through the use of
|
||||
the following functions:
|
||||
- PDMA_set_irq_handler()
|
||||
- PDMA_enable_irq()
|
||||
- PDMA_clear_irq()
|
||||
- PDMA_disable_irq()
|
||||
The PDMA_set_irq_handler() function is used to register PDMA channel interrupt
|
||||
handler functions with the driver. You must create and register an interrupt
|
||||
handler function for each interrupt driven PDMA channel used by the application.
|
||||
Use the PDMA_enable_irq() function to enable interrupts for the PDMA channels.
|
||||
Every time a PDMA channel completes the transfer of a buffer it causes a PDMA
|
||||
interrupt to occur and the PDMA driver will call the interrupt handler
|
||||
registered by the application for that PDMA channel.
|
||||
|
||||
*//*=========================================================================*/
|
||||
#ifndef __MSS_PERIPHERAL_DMA_H_
|
||||
#define __MSS_PERIPHERAL_DMA_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
The pdma_channel_id_t enumeration is used to identify peripheral DMA channels.
|
||||
It is used as function parameter to specify the PDMA channel used.
|
||||
*/
|
||||
typedef enum __pdma_channel_id
|
||||
{
|
||||
PDMA_CHANNEL_0 = 0,
|
||||
PDMA_CHANNEL_1,
|
||||
PDMA_CHANNEL_2,
|
||||
PDMA_CHANNEL_3,
|
||||
PDMA_CHANNEL_4,
|
||||
PDMA_CHANNEL_5,
|
||||
PDMA_CHANNEL_6,
|
||||
PDMA_CHANNEL_7
|
||||
} pdma_channel_id_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
The pdma_src_dest_t enumeration is used to specify the source or destination
|
||||
of transfers on a PDMA channel. It specifies which hardware peripheral will be
|
||||
the source or destination of DMA transfers. This allows the PDMA controller
|
||||
to use hardware flow control signals to avoid overrunning a
|
||||
destination peripheral with data it is not ready to receive, or attempting to
|
||||
transfer data from a peripheral while it has no data ready to transfer.
|
||||
The pdma_src_dest_t enumeration can also be used to specify that a PDMA channel
|
||||
is configured to transfer data between two memory mapped locations
|
||||
(memory to memory). No hardware data flow control is used by the PDMA
|
||||
controller in this configuration.
|
||||
This enumeration is used as parameter to function PDMA_configure().
|
||||
*/
|
||||
typedef enum __pdma_src_dest
|
||||
{
|
||||
PDMA_FROM_UART_0 = 0,
|
||||
PDMA_TO_UART_0,
|
||||
PDMA_FROM_UART_1,
|
||||
PDMA_TO_UART_1,
|
||||
PDMA_FROM_SPI_0,
|
||||
PDMA_TO_SPI_0,
|
||||
PDMA_FROM_SPI_1,
|
||||
PDMA_TO_SPI_1,
|
||||
PDMA_FROM_FPGA_1,
|
||||
PDMA_TO_FPGA_1,
|
||||
PDMA_FROM_FPGA_0,
|
||||
PDMA_TO_FPGA_0,
|
||||
PDMA_TO_ACE,
|
||||
PDMA_FROM_ACE,
|
||||
PDMA_MEM_TO_MEM
|
||||
} pdma_src_dest_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
The pdma_priority_ratio_t enumeration is used to configure the ratio of high
|
||||
priority to low priority PDMA channels. This ratio specifies how many DMA
|
||||
transfer opportunities will be given to high priority channels before a DMA
|
||||
transfer opportunity is given to a low priority channel when there are
|
||||
continuous requests from high priority channels. This enumeration is used as
|
||||
parameter to function PDMA_set_priority_ratio().
|
||||
*/
|
||||
typedef enum __pdma_priority_ratio_t
|
||||
{
|
||||
PDMA_ROUND_ROBIN = 0,
|
||||
PDMA_RATIO_HIGH_LOW_1_TO_1 = 1,
|
||||
PDMA_RATIO_HIGH_LOW_3_TO_1 = 3,
|
||||
PDMA_RATIO_HIGH_LOW_7_TO_1 = 7,
|
||||
PDMA_RATIO_HIGH_LOW_15_TO_1 = 15,
|
||||
PDMA_RATIO_HIGH_LOW_31_TO_1 = 31,
|
||||
PDMA_RATIO_HIGH_LOW_63_TO_1 = 63,
|
||||
PDMA_RATIO_HIGH_LOW_127_TO_1 = 127,
|
||||
PDMA_RATIO_HIGH_LOW_255_TO_1 = 255
|
||||
} pdma_priority_ratio_t;
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
The pdma_channel_isr_t type is a pointer to a PDMA channel interrupt handler
|
||||
function. It specifies the function prototype of functions that can be
|
||||
registered as PDMA channel interrupt handlers. It is used as parameter to
|
||||
function PDMA_set_irq_handler().
|
||||
*/
|
||||
typedef void (*pdma_channel_isr_t)( void );
|
||||
/***************************************************************************//**
|
||||
These constants are used to build the channel_cfg parameter of the
|
||||
PDMA_configure() function. They specify whether a channel is a high or low
|
||||
priority channel.
|
||||
*/
|
||||
#define PDMA_LOW_PRIORITY 0x0000
|
||||
#define PDMA_HIGH_PRIORITY 0x0200
|
||||
|
||||
/***************************************************************************//**
|
||||
These constants are used to build the channel_cfg parameter of the
|
||||
PDMA_configure() function. They specify the data width of the transfers
|
||||
performed by a PDMA channel.
|
||||
*/
|
||||
#define PDMA_BYTE_TRANSFER 0x0000 /* Byte transfers (8 bits) */
|
||||
#define PDMA_HALFWORD_TRANSFER 0x0004 /* Half-word transfers (16 bits) */
|
||||
#define PDMA_WORD_TRANSFER 0x0008 /* Word transfers (32 bits) */
|
||||
|
||||
/***************************************************************************//**
|
||||
These constants are used to build the channel_cfg parameter of the
|
||||
PDMA_configure() function. They specify the PDMA channel’s source and
|
||||
destination address increment.
|
||||
*/
|
||||
#define PDMA_NO_INC 0
|
||||
#define PDMA_INC_SRC_ONE_BYTE 0x0400
|
||||
#define PDMA_INC_SRC_TWO_BYTES 0x0800
|
||||
#define PDMA_INC_SRC_FOUR_BYTES 0x0C00
|
||||
#define PDMA_INC_DEST_ONE_BYTE 0x1000
|
||||
#define PDMA_INC_DEST_TWO_BYTES 0x2000
|
||||
#define PDMA_INC_DEST_FOUR_BYTES 0x3000
|
||||
|
||||
/***************************************************************************//**
|
||||
* Mask for various control register bits.
|
||||
*/
|
||||
#define PDMA_IRQ_ENABLE_MASK (uint32_t)0x00000040
|
||||
#define PDMA_PAUSE_MASK (uint32_t)0x00000010
|
||||
|
||||
/***************************************************************************//**
|
||||
These constants are used to specify the src_addr parameter to the PDMA_start()
|
||||
and PDMA_load_next_buffer() functions. They specify the receive register
|
||||
address of peripherals that can be the source of a DMA transfer.
|
||||
When a PDMA channel is configured for DMA transfers from a peripheral to memory,
|
||||
the constant specifying that peripheral’s receive register address must be used
|
||||
as the src_addr parameter.
|
||||
*/
|
||||
#define PDMA_SPI0_RX_REGISTER 0x40001010uL
|
||||
#define PDMA_SPI1_RX_REGISTER 0x40011010uL
|
||||
#define PDMA_UART0_RX_REGISTER 0x40000000uL
|
||||
#define PDMA_UART1_RX_REGISTER 0x40010000uL
|
||||
#define PDMA_ACE_PPE_DATAOUT 0x40021308uL
|
||||
|
||||
/***************************************************************************//**
|
||||
These constants are used to specify the dest_addr parameter to the PDMA_start()
|
||||
and PDMA_load_next_buffer() functions. They specify the transmit register
|
||||
address of peripherals that can be the destination of a DMA transfer.
|
||||
When a PDMA channel is configured for DMA transfers from memory to a peripheral,
|
||||
the constant specifying that peripheral’s transmit register address must be used
|
||||
as the dest_addr parameter.
|
||||
*/
|
||||
#define PDMA_SPI0_TX_REGISTER 0x40001014uL
|
||||
#define PDMA_SPI1_TX_REGISTER 0x40011014uL
|
||||
#define PDMA_UART0_TX_REGISTER 0x40000000uL
|
||||
#define PDMA_UART1_TX_REGISTER 0x40010000uL
|
||||
#define PDMA_ACE_SSE_DATAIN 0x40020700uL
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_DEFAULT_WRITE_ADJ constant provides a suitable default value for the
|
||||
PDMA_configure() function write_adjust parameter.
|
||||
*/
|
||||
#define PDMA_DEFAULT_WRITE_ADJ 10u
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_init() function initializes the peripheral DMA hardware and driver
|
||||
internal data. It resets the PDMA and it also clears any pending PDMA
|
||||
interrupts in the Cortex-M3 interrupt controller. When the function exits, it
|
||||
takes the PDMA block out of reset.
|
||||
*/
|
||||
void PDMA_init( void );
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_configure() function configures a PDMA channel.
|
||||
It specifies:
|
||||
- The peripheral which will be the source or destination of the DMA transfer.
|
||||
- Whether the DMA channel will be a high or low priority channel
|
||||
- The source and destination address increment that will take place after
|
||||
each transfer.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@param src_dest
|
||||
The src_dest parameter specifies the source or destination of the DMA
|
||||
transfers that will be performed. It can be one of the following:
|
||||
- PDMA_FROM_UART_0
|
||||
- PDMA_TO_UART_0
|
||||
- PDMA_FROM_UART_1
|
||||
- PDMA_TO_UART_1
|
||||
- PDMA_FROM_SPI_0
|
||||
- PDMA_TO_SPI_0
|
||||
- PDMA_FROM_SPI_1
|
||||
- PDMA_TO_SPI_1
|
||||
- PDMA_FROM_FPGA_1
|
||||
- PDMA_TO_FPGA_1
|
||||
- PDMA_FROM_FPGA_0
|
||||
- PDMA_TO_FPGA_0
|
||||
- PDMA_TO_ACE
|
||||
- PDMA_FROM_ACE
|
||||
- PDMA_MEM_TO_MEM
|
||||
|
||||
@param channel_cfg
|
||||
The channel_cfg parameter specifies the configuration of the PDMA channel.
|
||||
The configuration includes:
|
||||
- channel priority
|
||||
- transfer size
|
||||
- source and/or destination address increment
|
||||
The channel_cfg parameter value is a logical OR of:
|
||||
One of the following to specify the channel priority:
|
||||
- PDMA_LOW_PRIORITY
|
||||
- PDMA_HIGH_PRIORITY
|
||||
One of the following to specify the transfer size:
|
||||
- PDMA_BYTE_TRANSFER
|
||||
- PDMA_HALFWORD_TRANSFER
|
||||
- PDMA_WORD_TRANSFER
|
||||
One or two of the following to specify the source and/or destination address
|
||||
increment:
|
||||
- PDMA_NO_INC
|
||||
- PDMA_INC_SRC_ONE_BYTE
|
||||
- PDMA_INC_SRC_TWO_BYTES
|
||||
- PDMA_INC_SRC_FOUR_BYTES
|
||||
- PDMA_INC_DEST_ONE_BYTE
|
||||
- PDMA_INC_DEST_TWO_BYTES
|
||||
- PDMA_INC_DEST_FOUR_BYTES
|
||||
|
||||
@param write_adjust
|
||||
The write_adjust parameter specifies the number of Cortex-M3 clock cycles
|
||||
the PDMA controller will wait before attempting another transfer cycle. This
|
||||
delay is necessary when peripherals are used as destination of a DMA transfer
|
||||
to ensure the DMA controller interprets the state of the peripheral’s ready
|
||||
signal only after data has actually been written to the peripheral. This delay
|
||||
accounts for posted writes (dump and run) for write accesses to peripherals.
|
||||
The effect of posted writes is that if the PDMA performs a write operation to
|
||||
a peripheral, the data is not actually written into the peripheral until
|
||||
sometime after the PDMA controller thinks it is written.
|
||||
A suitable value for write_adjust depends on the target of the DMA transfer.
|
||||
Guidelines for choosing this value are as follows:
|
||||
• The PDMA_DEFAULT_WRITE_ADJ constant provides a suitable default value
|
||||
for the write_adjust parameter when the PDMA channel is configured for
|
||||
transfers with MSS peripherals.
|
||||
• The PDMA_DEFAULT_WRITE_ADJ constant can also be used for DMA transfers
|
||||
with FPGA fabric implemented peripherals making use of the DMAREADY0 or
|
||||
DMAREADY1fabric interface signal to indicate that the peripheral is
|
||||
ready for another DMA transfer.
|
||||
• The write_adjust parameter can be set to zero to achieve maximum transfer
|
||||
speed for genuine memory to memory transfers.
|
||||
• The internal latency of FPGA implemented peripherals will decide the
|
||||
write_adjust value for fabric peripherals that do not use the DMAREADY0
|
||||
or DMAREADY1 fabric interface signals. You need to check the fabric
|
||||
peripheral documentation for the value to use.
|
||||
|
||||
Example:
|
||||
@code
|
||||
PDMA_configure
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
PDMA_TO_SPI_1,
|
||||
PDMA_LOW_PRIORITY | PDMA_BYTE_TRANSFER | PDMA_INC_SRC_ONE_BYTE,
|
||||
PDMA_DEFAULT_WRITE_ADJ
|
||||
);
|
||||
@endcode
|
||||
*/
|
||||
void PDMA_configure
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
pdma_src_dest_t src_dest,
|
||||
uint32_t channel_cfg,
|
||||
uint8_t write_adjust
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_set_priority_ratio() function sets the ratio of high priority to low
|
||||
priority DMA access opportunities. This ratio is used by the PDMA controller
|
||||
arbiter to decide which PDMA channel will be given the opportunity to perform
|
||||
a transfer when multiple PDMA channels are requesting to transfer data at the
|
||||
same time. The priority ratio specifies how many DMA transfer opportunities
|
||||
will be given to high priority channels before a DMA transfer opportunity is
|
||||
given to a low priority channel when there are continuous requests from high
|
||||
priority channels.
|
||||
|
||||
@param priority_ratio
|
||||
The priority_ratio parameter specifies the ratio of DMA access opportunities
|
||||
given to high priority channels versus low priority channels.
|
||||
Allowed values for this parameter are:
|
||||
- PDMA_ROUND_ROBIN
|
||||
- PDMA_RATIO_HIGH_LOW_1_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_3_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_7_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_15_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_31_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_63_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_127_TO_1
|
||||
- PDMA_RATIO_HIGH_LOW_255_TO_1
|
||||
|
||||
Example:
|
||||
@code
|
||||
PDMA_set_priority_ratio( PDMA_ROUND_ROBIN );
|
||||
@endcode
|
||||
*/
|
||||
static __INLINE void PDMA_set_priority_ratio
|
||||
(
|
||||
pdma_priority_ratio_t priority_ratio
|
||||
)
|
||||
{
|
||||
PDMA->RATIO_HIGH_LOW = (uint32_t)priority_ratio;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_start() function initiates a DMA transfer. It specifies the source
|
||||
and destination address of the transfer as well as the number of transfers
|
||||
that must take place. The source and destination addresses can be the address
|
||||
of peripheral registers.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@param src_addr
|
||||
The src_addr parameter specifies the address location of the data to be
|
||||
transferred. You must ensure that this source address is consistent with the
|
||||
DMA source configured for the selected channel using the PDMA_configure()
|
||||
function.
|
||||
For DMA transfers from MSS peripheral to memory, the following src_addr
|
||||
parameter values are allowed:
|
||||
• PDMA_SPI0_RX_REGISTER
|
||||
• PDMA_SPI1_RX_REGISTER
|
||||
• PDMA_UART0_RX_REGISTER
|
||||
• PDMA_UART1_RX_REGISTER
|
||||
• PDMA_ACE_PPE_DATAOUT
|
||||
For DMA transfers from FPGA fabric peripheral to memory, the following
|
||||
src_addr parameter values are allowed:
|
||||
• An address in the FPGA fabric address space (0x40050000-0x400FFFFF)
|
||||
For DMA transfers from memory to MSS peripheral, or from memory to FPGA
|
||||
fabric peripheral, or from memory to memory, the following src_addr
|
||||
parameter values are allowed:
|
||||
• Any memory mapped address.
|
||||
|
||||
@param dest_addr
|
||||
The dest_addr parameter specifies the destination address of the PDMA
|
||||
transfer. You must ensure that this matches with the DMA destination
|
||||
configured for the selected channel.
|
||||
For DMA transfers from memory to MSS peripheral, the following dest_addr parameter values are allowed:
|
||||
• PDMA_SPI0_TX_REGISTER
|
||||
• PDMA_SPI1_TX_REGISTER
|
||||
• PDMA_UART0_TX_REGISTER
|
||||
• PDMA_UART1_TX_REGISTER
|
||||
• PDMA_ACE_SSE_DATAIN
|
||||
For DMA transfers from memory to FPGA fabric peripheral, the following
|
||||
dest_addr parameter values are allowed:
|
||||
• An address in the FPGA fabric address space (0x40050000-0x400FFFFF)
|
||||
For DMA transfers from MSS peripheral to memory, or from FPGA fabric
|
||||
peripheral to memory, or from memory to memory, the following dest_addr
|
||||
parameter values are allowed:
|
||||
• Any memory mapped address.
|
||||
|
||||
@param transfer_count
|
||||
The transfer_count parameter specifies the number of transfers to be
|
||||
performed. It is the number of bytes to transfer if the PDMA channel is
|
||||
configured for byte transfer, the number of half-words to transfer if the
|
||||
PDMA channel is configured for half-word transfer, or the number of words
|
||||
to transfer if the PDMA channel is configured for word transfer.
|
||||
|
||||
Example:
|
||||
@code
|
||||
PDMA_start
|
||||
(
|
||||
PDMA_CHANNEL_3,
|
||||
PDMA_SPI1_RX_REGISTER,
|
||||
(uint32_t)slave_rx_buffer,
|
||||
sizeof(slave_rx_buffer)
|
||||
);
|
||||
@endcode
|
||||
*/
|
||||
void PDMA_start
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
uint32_t src_addr,
|
||||
uint32_t dest_addr,
|
||||
uint16_t transfer_count
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_load_next_buffer() function sets the next buffer to be transferred.
|
||||
This function is called after a transfer has been initiated using the
|
||||
PDMA_start() function. Its purpose is to keep feeding a PDMA channel with data
|
||||
buffers.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@param src_addr
|
||||
The src_addr parameter specifies the address location of the data to be
|
||||
transferred. You must ensure that this source address is consistent with the
|
||||
DMA source configured for the selected channel using the PDMA_configure()
|
||||
function.
|
||||
For DMA transfers from MSS peripheral to memory, the following src_addr parameter values are allowed:
|
||||
• PDMA_SPI0_RX_REGISTER
|
||||
• PDMA_SPI1_RX_REGISTER
|
||||
• PDMA_UART0_RX_REGISTER
|
||||
• PDMA_UART1_RX_REGISTER
|
||||
• PDMA_ACE_PPE_DATAOUT
|
||||
For DMA transfers from FPGA fabric peripheral to memory, the following src_addr parameter values are allowed:
|
||||
• An address in the FPGA fabric address space (0x40050000-0x400FFFFF)
|
||||
For DMA transfers from memory to MSS peripheral, or from memory to FPGA fabric peripheral, or from memory to memory, the following src_addr parameter values are allowed:
|
||||
• Any memory mapped address.
|
||||
|
||||
@param dest_addr
|
||||
The dest_addr parameter specifies the destination address of the PDMA
|
||||
transfer. You must ensure that this matches with the DMA destination
|
||||
configured for the selected channel.
|
||||
For DMA transfers from memory to MSS peripheral, the following dest_addr parameter values are allowed:
|
||||
• PDMA_SPI0_TX_REGISTER
|
||||
• PDMA_SPI1_TX_REGISTER
|
||||
• PDMA_UART0_TX_REGISTER
|
||||
• PDMA_UART1_TX_REGISTER
|
||||
• PDMA_ACE_SSE_DATAIN
|
||||
For DMA transfers from memory to FPGA fabric peripheral, the following dest_addr parameter values are allowed:
|
||||
• An address in the FPGA fabric address space (0x40050000-0x400FFFFF)
|
||||
For DMA transfers from MSS peripheral to memory, or from FPGA fabric peripheral to memory, or from memory to memory, the following dest_addr parameter values are allowed:
|
||||
• Any memory mapped address.
|
||||
|
||||
@param transfer_count
|
||||
The transfer_count parameter specifies the number of transfers to be
|
||||
performed. It is the number of bytes to transfer if the PDMA channel is
|
||||
configured for byte transfer, the number of half-words to transfer if the
|
||||
PDMA channel is configured for half-word transfer or the number of words to
|
||||
transfer if the PDMA channel is configured for word transfer.
|
||||
|
||||
Example:
|
||||
@code
|
||||
void write_cmd_data
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
const uint8_t * cmd_buffer,
|
||||
uint16_t cmd_byte_size,
|
||||
uint8_t * data_buffer,
|
||||
uint16_t data_byte_size
|
||||
)
|
||||
{
|
||||
uint32_t transfer_size;
|
||||
|
||||
transfer_size = cmd_byte_size + data_byte_size;
|
||||
|
||||
MSS_SPI_disable( this_spi );
|
||||
MSS_SPI_set_transfer_byte_count( this_spi, transfer_size );
|
||||
|
||||
PDMA_start
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
(uint32_t)cmd_buffer,
|
||||
PDMA_SPI1_TX_REGISTER,
|
||||
cmd_byte_size
|
||||
);
|
||||
|
||||
PDMA_load_next_buffer
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
(uint32_t)data_buffer,
|
||||
PDMA_SPI1_TX_REGISTER,
|
||||
data_byte_size
|
||||
);
|
||||
|
||||
MSS_SPI_enable( this_spi );
|
||||
|
||||
while ( !MSS_SPI_tx_done(this_spi) )
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
void PDMA_load_next_buffer
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
uint32_t src_addr,
|
||||
uint32_t dest_addr,
|
||||
uint16_t transfer_count
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_status() function returns the status of a DMA channel.
|
||||
The returned value indicates if transfers have been completed using buffer A
|
||||
or buffer B of the PDMA hardware block.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@return
|
||||
bit 0 of the return value indicates if buffer A has been trasnfered. It is
|
||||
set to 1 if the transfer has completed.
|
||||
bit 1 of the return value indicates if buffer B has been transfered. It is
|
||||
set to 1 if the transfer has completed.
|
||||
*/
|
||||
uint32_t PDMA_status
|
||||
(
|
||||
pdma_channel_id_t channel_id
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_pause() function temporarily pauses a PDMA transfer taking place on
|
||||
the specified PDMA channel. The transfer can later be resumed by using the
|
||||
PDMA_resume() function.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
*/
|
||||
static __INLINE void PDMA_pause( pdma_channel_id_t channel_id )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL |= PDMA_PAUSE_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_resume() function resumes a transfer previously paused using the
|
||||
PDMA_pause() function.
|
||||
|
||||
@param channel_id The channel_id parameter identifies the PDMA channel
|
||||
used by the function.
|
||||
*/
|
||||
static __INLINE void PDMA_resume( pdma_channel_id_t channel_id )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL &= ~PDMA_PAUSE_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_enable_irq() enables the PDMA hardware to generate an interrupt when
|
||||
a DMA transfer completes on the specified PDMA channel. This function also
|
||||
enables the PDMA interrupt in the Cortex-M3 interrupt controller.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
*/
|
||||
void PDMA_enable_irq( pdma_channel_id_t channel_id );
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_disable_irq() disables interrupts for a specific PDMA channel.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
*/
|
||||
static __INLINE void PDMA_disable_irq( pdma_channel_id_t channel_id )
|
||||
{
|
||||
PDMA->CHANNEL[channel_id].CRTL &= ~PDMA_IRQ_ENABLE_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_set_irq_handler() function registers a handler function for
|
||||
interrupts generated on the completion of a transfer on a specific PDMA
|
||||
channel. This function also enables the PDMA interrupt both in the PDMA
|
||||
controller and in the Cortex-M3 interrupt controller.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
|
||||
@param handler
|
||||
The handler parameter is a pointer to the function that will be called when
|
||||
a transfer completes on the PDMA channel identified by channel_id and the
|
||||
interrupt is enabled for that channel.
|
||||
|
||||
Example:
|
||||
@code
|
||||
void slave_dma_irq_handler( void )
|
||||
{
|
||||
if ( g_spi1_rx_buffer[2] == 0x99 )
|
||||
{
|
||||
PDMA_load_next_buffer
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
(uint32_t)g_spi1_tx_buffer_b,
|
||||
PDMA_SPI1_TX_REGISTER,
|
||||
sizeof(g_spi1_tx_buffer_b)
|
||||
);
|
||||
}
|
||||
PDMA_disable_irq( PDMA_CHANNEL_3 );
|
||||
}
|
||||
|
||||
void setup_dma( void )
|
||||
{
|
||||
PDMA_init();
|
||||
PDMA_configure
|
||||
(
|
||||
PDMA_CHANNEL_0,
|
||||
PDMA_TO_SPI_1,
|
||||
PDMA_LOW_PRIORITY | PDMA_BYTE_TRANSFER | PDMA_INC_SRC_ONE_BYTE
|
||||
);
|
||||
PDMA_configure
|
||||
(
|
||||
PDMA_CHANNEL_3,
|
||||
PDMA_FROM_SPI_1,
|
||||
PDMA_HIGH_PRIORITY | PDMA_BYTE_TRANSFER | PDMA_INC_DEST_ONE_BYTE
|
||||
);
|
||||
PDMA_set_irq_handler( PDMA_CHANNEL_3, slave_dma_irq_handler );
|
||||
PDMA_start( PDMA_CHANNEL_3, PDMA_SPI1_RX_REGISTER, (uint32_t)g_spi1_rx_buffer, 3 );
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
void PDMA_set_irq_handler
|
||||
(
|
||||
pdma_channel_id_t channel_id,
|
||||
pdma_channel_isr_t handler
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The PDMA_clear_irq() function clears interrupts for a specific PDMA channel.
|
||||
This function also clears the PDMA interrupt in the Cortex-M3 NVIC.
|
||||
|
||||
@param channel_id
|
||||
The channel_id parameter identifies the PDMA channel used by the function.
|
||||
*/
|
||||
void PDMA_clear_irq
|
||||
(
|
||||
pdma_channel_id_t channel_id
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_PERIPHERAL_DMA_H_ */
|
|
@ -0,0 +1,610 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2008 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion microcontroller subsystem SPI bare metal software driver
|
||||
* implementation.
|
||||
*
|
||||
* SVN $Revision: 2176 $
|
||||
* SVN $Date: 2010-02-15 21:04:22 +0000 (Mon, 15 Feb 2010) $
|
||||
*/
|
||||
#include "mss_spi.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
MSS SPI can operate as master or slave.
|
||||
*/
|
||||
#define MSS_SPI_MODE_SLAVE (uint32_t)0
|
||||
#define MSS_SPI_MODE_MASTER (uint32_t)1
|
||||
|
||||
/***************************************************************************//**
|
||||
* Mask of transfer protocol and SPO, SPH bits within control register.
|
||||
*/
|
||||
#define PROTOCOL_MODE_MASK (uint32_t)0x030000C0
|
||||
|
||||
/***************************************************************************//**
|
||||
* Mask of theframe count bits within the SPI control register.
|
||||
*/
|
||||
#define TXRXDFCOUNT_MASK (uint32_t)0x00FFFF00
|
||||
#define TXRXDFCOUNT_SHIFT (uint32_t)8
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPI hardware FIFO depth.
|
||||
*/
|
||||
#define RX_FIFO_SIZE 4u
|
||||
|
||||
/***************************************************************************//**
|
||||
Marker used to detect that the configuration has not been selected for a
|
||||
specific slave when operating as a master.
|
||||
*/
|
||||
#define NOT_CONFIGURED 0xFFFFFFFF
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPI instance data structures for SPI0 and SPI1. A pointer to these data
|
||||
* structures must be used as first parameter to any of the SPI driver functions
|
||||
* to identify the SPI hardware block that will perform the requested operation.
|
||||
*/
|
||||
mss_spi_instance_t g_mss_spi0;
|
||||
mss_spi_instance_t g_mss_spi1;
|
||||
|
||||
/***************************************************************************//**
|
||||
SPI0 interrupt service routine
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void SPI0_IRQHandler( void );
|
||||
#else
|
||||
void SPI0_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
SPI1 interrupt service routine
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void SPI1_IRQHandler( void );
|
||||
#else
|
||||
void SPI1_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_init()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_init
|
||||
(
|
||||
mss_spi_instance_t * this_spi
|
||||
)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
if (this_spi == &g_mss_spi0)
|
||||
{
|
||||
this_spi->hw_reg = SPI0;
|
||||
this_spi->hw_reg_bit = SPI0_BITBAND;
|
||||
this_spi->irqn = SPI0_IRQn;
|
||||
|
||||
/* reset SPI0 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_SPI0_SOFTRESET_MASK;
|
||||
/* Clear any previously pended SPI0 interrupt */
|
||||
NVIC_ClearPendingIRQ( SPI0_IRQn );
|
||||
/* Take SPI0 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_SPI0_SOFTRESET_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_spi->hw_reg = SPI1;
|
||||
this_spi->hw_reg_bit = SPI1_BITBAND;
|
||||
this_spi->irqn = SPI1_IRQn;
|
||||
|
||||
/* reset SPI1 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_SPI1_SOFTRESET_MASK;
|
||||
/* Clear any previously pended SPI1 interrupt */
|
||||
NVIC_ClearPendingIRQ( SPI1_IRQn );
|
||||
/* Take SPI1 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_SPI1_SOFTRESET_MASK;
|
||||
}
|
||||
|
||||
this_spi->frame_rx_handler = 0U;
|
||||
this_spi->slave_tx_frame = 0U;
|
||||
|
||||
this_spi->block_rx_handler = 0U;
|
||||
|
||||
this_spi->slave_tx_buffer = 0U;
|
||||
this_spi->slave_tx_size = 0U;
|
||||
this_spi->slave_tx_idx = 0U;
|
||||
|
||||
for ( i = 0u; i < (uint16_t)MSS_SPI_MAX_NB_OF_SLAVES; ++i )
|
||||
{
|
||||
this_spi->slaves_cfg[i].ctrl_reg = NOT_CONFIGURED;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_configure_slave_mode()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_configure_slave_mode
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_protocol_mode_t protocol_mode,
|
||||
mss_spi_pclk_div_t clk_rate,
|
||||
uint8_t frame_bit_length
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
ASSERT( frame_bit_length <= 32 );
|
||||
|
||||
/* Set the mode. */
|
||||
this_spi->hw_reg_bit->CTRL_MASTER = MSS_SPI_MODE_SLAVE;
|
||||
|
||||
/* Set the clock rate. */
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~PROTOCOL_MODE_MASK) | (uint32_t)protocol_mode;
|
||||
this_spi->hw_reg->CLK_GEN = (uint32_t)clk_rate;
|
||||
|
||||
/* Set default frame size to byte size and number of data frames to 1. */
|
||||
this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ((uint32_t)1 << TXRXDFCOUNT_SHIFT);
|
||||
this_spi->hw_reg->TXRXDF_SIZE = frame_bit_length;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_configure_master_mode()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_configure_master_mode
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_slave_t slave,
|
||||
mss_spi_protocol_mode_t protocol_mode,
|
||||
mss_spi_pclk_div_t clk_rate,
|
||||
uint8_t frame_bit_length
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
ASSERT( slave < MSS_SPI_MAX_NB_OF_SLAVES );
|
||||
ASSERT( frame_bit_length <= 32 );
|
||||
|
||||
/* Set the mode. */
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg_bit->CTRL_MASTER = MSS_SPI_MODE_MASTER;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
|
||||
/*
|
||||
* Keep track of the required register configuration for this slave. These
|
||||
* values will be used by the MSS_SPI_set_slave_select() function to configure
|
||||
* the master to match the slave being selected.
|
||||
*/
|
||||
if ( slave < MSS_SPI_MAX_NB_OF_SLAVES )
|
||||
{
|
||||
this_spi->slaves_cfg[slave].ctrl_reg = 0x00000002uL | (uint32_t)protocol_mode | ((uint32_t)1 << TXRXDFCOUNT_SHIFT);
|
||||
this_spi->slaves_cfg[slave].txrxdf_size_reg = frame_bit_length;
|
||||
this_spi->slaves_cfg[slave].clk_gen = (uint8_t)clk_rate;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_set_slave_select()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_set_slave_select
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_slave_t slave
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI master. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_MASTER );
|
||||
ASSERT( this_spi->slaves_cfg[slave].ctrl_reg != NOT_CONFIGURED );
|
||||
|
||||
/* Set the clock rate. */
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg->CONTROL = this_spi->slaves_cfg[slave].ctrl_reg;
|
||||
this_spi->hw_reg->CLK_GEN = this_spi->slaves_cfg[slave].clk_gen;
|
||||
this_spi->hw_reg->TXRXDF_SIZE = this_spi->slaves_cfg[slave].txrxdf_size_reg;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
|
||||
/* Set slave select */
|
||||
this_spi->hw_reg->SLAVE_SELECT |= ((uint32_t)1 << (uint32_t)slave);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_clear_slave_select()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_clear_slave_select
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_slave_t slave
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI master. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_MASTER );
|
||||
|
||||
this_spi->hw_reg->SLAVE_SELECT &= ~((uint32_t)1 << (uint32_t)slave);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_transfer_frame()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
uint32_t MSS_SPI_transfer_frame
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
uint32_t tx_bits
|
||||
)
|
||||
{
|
||||
volatile uint32_t dummy;
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI master. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_MASTER );
|
||||
|
||||
/* Flush Rx FIFO. */
|
||||
while ( this_spi->hw_reg_bit->STATUS_RX_RDY == 1U )
|
||||
{
|
||||
dummy = this_spi->hw_reg->RX_DATA;
|
||||
dummy = dummy; /* Prevent Lint warning. */
|
||||
}
|
||||
|
||||
/* Send frame. */
|
||||
this_spi->hw_reg->TX_DATA = tx_bits;
|
||||
|
||||
/* Wait for frame Tx to complete. */
|
||||
while ( this_spi->hw_reg_bit->STATUS_TX_DONE == 0U )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/* Read received frame. */
|
||||
/* Wait for Rx complete. */
|
||||
while ( this_spi->hw_reg_bit->STATUS_RX_RDY == 0U )
|
||||
{
|
||||
;
|
||||
}
|
||||
/* Return Rx data. */
|
||||
return( this_spi->hw_reg->RX_DATA );
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_transfer_block()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_transfer_block
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
const uint8_t * cmd_buffer,
|
||||
uint16_t cmd_byte_size,
|
||||
uint8_t * rd_buffer,
|
||||
uint16_t rd_byte_size
|
||||
)
|
||||
{
|
||||
uint16_t transfer_idx = 0U;
|
||||
uint16_t tx_idx;
|
||||
uint16_t rx_idx;
|
||||
uint32_t frame_count;
|
||||
volatile uint32_t rx_raw;
|
||||
uint16_t transit = 0U;
|
||||
|
||||
uint16_t transfer_size; /* Total number of bytes transfered. */
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI master. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_MASTER );
|
||||
|
||||
/* Compute number of bytes to transfer. */
|
||||
transfer_size = cmd_byte_size + rd_byte_size;
|
||||
|
||||
/* Adjust to 1 byte transfer to cater for DMA transfers. */
|
||||
if ( transfer_size == 0U )
|
||||
{
|
||||
frame_count = 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_count = transfer_size;
|
||||
}
|
||||
|
||||
/* Set frame size to 8 bits and the frame count to the tansfer size. */
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ( (frame_count << TXRXDFCOUNT_SHIFT) & TXRXDFCOUNT_MASK);
|
||||
this_spi->hw_reg->TXRXDF_SIZE = 8U;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
|
||||
/* Flush the receive FIFO. */
|
||||
while ( !this_spi->hw_reg_bit->STATUS_RX_FIFO_EMPTY )
|
||||
{
|
||||
rx_raw = this_spi->hw_reg->RX_DATA;
|
||||
}
|
||||
|
||||
tx_idx = 0u;
|
||||
rx_idx = 0u;
|
||||
if ( tx_idx < cmd_byte_size )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx];
|
||||
++tx_idx;
|
||||
++transit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( tx_idx < transfer_size )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = 0x00U;
|
||||
++tx_idx;
|
||||
++transit;
|
||||
}
|
||||
}
|
||||
/* Perform the remainder of the transfer by sending a byte every time a byte
|
||||
* has been received. This should ensure that no Rx overflow can happen in
|
||||
* case of an interrupt occurs during this function. */
|
||||
while ( transfer_idx < transfer_size )
|
||||
{
|
||||
if ( !this_spi->hw_reg_bit->STATUS_RX_FIFO_EMPTY )
|
||||
{
|
||||
/* Process received byte. */
|
||||
rx_raw = this_spi->hw_reg->RX_DATA;
|
||||
if ( transfer_idx >= cmd_byte_size )
|
||||
{
|
||||
if ( rx_idx < rd_byte_size )
|
||||
{
|
||||
rd_buffer[rx_idx] = (uint8_t)rx_raw;
|
||||
}
|
||||
++rx_idx;
|
||||
}
|
||||
++transfer_idx;
|
||||
--transit;
|
||||
}
|
||||
|
||||
if ( !this_spi->hw_reg_bit->STATUS_TX_FIFO_FULL )
|
||||
{
|
||||
if (transit < RX_FIFO_SIZE)
|
||||
{
|
||||
/* Send another byte. */
|
||||
if ( tx_idx < cmd_byte_size )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx];
|
||||
++tx_idx;
|
||||
++transit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( tx_idx < transfer_size )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = 0x00U;
|
||||
++tx_idx;
|
||||
++transit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_set_frame_rx_handler()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_set_frame_rx_handler
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
mss_spi_frame_rx_handler_t rx_handler
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI slave. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_SLAVE );
|
||||
|
||||
/* Disable block Rx handler as they are mutually exclusive. */
|
||||
this_spi->block_rx_handler = 0U;
|
||||
|
||||
/* Keep a copy of the pointer to the rx hnadler function. */
|
||||
this_spi->frame_rx_handler = rx_handler;
|
||||
|
||||
/* Enable Rx interrupt. */
|
||||
this_spi->hw_reg_bit->CTRL_RX_INT_EN = 1U;
|
||||
NVIC_EnableIRQ( this_spi->irqn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_set_slave_tx_frame()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_set_slave_tx_frame
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
uint32_t frame_value
|
||||
)
|
||||
{
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI slave. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_SLAVE );
|
||||
|
||||
/* Disable slave block tx buffer as it is mutually exclusive with frame
|
||||
* level handling. */
|
||||
this_spi->slave_tx_buffer = 0U;
|
||||
this_spi->slave_tx_size = 0U;
|
||||
this_spi->slave_tx_idx = 0U;
|
||||
|
||||
/* Keep a copy of the slave tx frame value. */
|
||||
this_spi->slave_tx_frame = frame_value;
|
||||
|
||||
/* Load frame into Tx data register. */
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame;
|
||||
|
||||
/* Enable Tx Done interrupt in order to reload the slave Tx frame after each
|
||||
* time it has been sent. */
|
||||
this_spi->hw_reg_bit->CTRL_TX_INT_EN = 1U;
|
||||
NVIC_EnableIRQ( this_spi->irqn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* MSS_SPI_set_slave_block_buffers()
|
||||
* See "mss_spi.h" for details of how to use this function.
|
||||
*/
|
||||
void MSS_SPI_set_slave_block_buffers
|
||||
(
|
||||
mss_spi_instance_t * this_spi,
|
||||
const uint8_t * tx_buffer,
|
||||
uint32_t tx_buff_size,
|
||||
uint8_t * rx_buffer,
|
||||
uint32_t rx_buff_size,
|
||||
mss_spi_block_rx_handler_t block_rx_handler
|
||||
)
|
||||
{
|
||||
uint32_t frame_count;
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
/* This function is only intended to be used with an SPI slave. */
|
||||
ASSERT( this_spi->hw_reg_bit->CTRL_MASTER == MSS_SPI_MODE_SLAVE );
|
||||
|
||||
/* Disable Rx frame handler as it is mutually exclusive with block rx handler. */
|
||||
this_spi->frame_rx_handler = 0U;
|
||||
|
||||
/* Keep a copy of the pointer to the block rx handler function. */
|
||||
this_spi->block_rx_handler = block_rx_handler;
|
||||
|
||||
this_spi->slave_rx_buffer = rx_buffer;
|
||||
this_spi->slave_rx_size = rx_buff_size;
|
||||
this_spi->slave_rx_idx = 0U;
|
||||
|
||||
/**/
|
||||
this_spi->slave_tx_buffer = tx_buffer;
|
||||
this_spi->slave_tx_size = tx_buff_size;
|
||||
this_spi->slave_tx_idx = 0U;
|
||||
|
||||
frame_count = rx_buff_size;
|
||||
|
||||
/**/
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 0U;
|
||||
this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | (frame_count << TXRXDFCOUNT_SHIFT);
|
||||
this_spi->hw_reg->TXRXDF_SIZE = 8U;
|
||||
this_spi->hw_reg_bit->CTRL_ENABLE = 1U;
|
||||
|
||||
/* Load the transmit FIFO. */
|
||||
while ( !(this_spi->hw_reg_bit->STATUS_TX_FIFO_FULL) && ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_buffer[this_spi->slave_tx_idx];
|
||||
++this_spi->slave_tx_idx;
|
||||
}
|
||||
|
||||
/* Enable Rx interrupt. */
|
||||
this_spi->hw_reg_bit->CTRL_RX_INT_EN = 1U;
|
||||
NVIC_EnableIRQ( this_spi->irqn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPI interrupt service routine.
|
||||
*/
|
||||
static void mss_spi_isr
|
||||
(
|
||||
mss_spi_instance_t * this_spi
|
||||
)
|
||||
{
|
||||
uint32_t rx_frame;
|
||||
|
||||
ASSERT( (this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1) );
|
||||
|
||||
if ( this_spi->hw_reg_bit->MIS_RX_RDY )
|
||||
{
|
||||
while( !this_spi->hw_reg_bit->STATUS_RX_FIFO_EMPTY )
|
||||
{
|
||||
rx_frame = this_spi->hw_reg->RX_DATA;
|
||||
if ( this_spi->frame_rx_handler != 0U )
|
||||
{
|
||||
/* Single frame handling mode. */
|
||||
this_spi->frame_rx_handler( rx_frame );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( this_spi->block_rx_handler != 0U )
|
||||
{
|
||||
/* Block handling mode. */
|
||||
if ( this_spi->slave_rx_idx < this_spi->slave_rx_size )
|
||||
{
|
||||
this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame;
|
||||
++this_spi->slave_rx_idx;
|
||||
if ( this_spi->slave_rx_idx == this_spi->slave_rx_size )
|
||||
{
|
||||
(*this_spi->block_rx_handler)( this_spi->slave_rx_buffer, this_spi->slave_rx_size );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Feed transmit FIFO. */
|
||||
if ( !(this_spi->hw_reg_bit->STATUS_TX_FIFO_FULL) && ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_buffer[this_spi->slave_tx_idx];
|
||||
++this_spi->slave_tx_idx;
|
||||
}
|
||||
}
|
||||
this_spi->hw_reg_bit->INT_CLEAR_RX_RDY = 1U;
|
||||
}
|
||||
|
||||
if ( this_spi->hw_reg_bit->MIS_TX_DONE )
|
||||
{
|
||||
if ( this_spi->slave_tx_buffer != 0U )
|
||||
{
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_buffer[this_spi->slave_tx_idx];
|
||||
++this_spi->slave_tx_idx;
|
||||
if ( this_spi->slave_tx_idx >= this_spi->slave_tx_size )
|
||||
{
|
||||
this_spi->slave_tx_idx = 0U;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reload slave tx frame into Tx data register. */
|
||||
this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPIO interrupt service routine.
|
||||
* Please note that the name of this ISR is defined as part of the SmartFusion
|
||||
* CMSIS startup code.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void SPI0_IRQHandler( void )
|
||||
#else
|
||||
void SPI0_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
mss_spi_isr( &g_mss_spi0 );
|
||||
NVIC_ClearPendingIRQ( SPI0_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* SPI1 interrupt service routine.
|
||||
* Please note that the name of this ISR is defined as part of the SmartFusion
|
||||
* CMSIS startup code.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void SPI1_IRQHandler( void )
|
||||
#else
|
||||
void SPI1_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
mss_spi_isr( &g_mss_spi1 );
|
||||
NVIC_ClearPendingIRQ( SPI1_IRQn );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,458 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2007 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion Microcontroller Subsystem UART bare metal software driver
|
||||
* implementation.
|
||||
*
|
||||
* SVN $Revision: 1898 $
|
||||
* SVN $Date: 2009-12-21 17:27:57 +0000 (Mon, 21 Dec 2009) $
|
||||
*/
|
||||
#include "mss_uart.h"
|
||||
#include "../../CMSIS/mss_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* defines
|
||||
*/
|
||||
#define TX_READY 0x01U
|
||||
#define TX_COMPLETE 0U
|
||||
|
||||
#define TX_FIFO_SIZE 16U
|
||||
|
||||
#define FCR_TRIG_LEVEL_MASK 0xC0U
|
||||
|
||||
#define IIRF_MASK 0x0FU
|
||||
|
||||
/*******************************************************************************
|
||||
* Possible values for Interrupt Identification Register Field.
|
||||
*/
|
||||
#define IIRF_MODEM_STATUS 0x00U
|
||||
#define IIRF_THRE 0x02U
|
||||
#define IIRF_RX_DATA 0x04U
|
||||
#define IIRF_RX_LINE_STATUS 0x06U
|
||||
#define IIRF_DATA_TIMEOUT 0x0CU
|
||||
|
||||
/*******************************************************************************
|
||||
* Cortex-M3 interrupt handler functions implemented as part of the MSS UART
|
||||
* driver.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void UART0_IRQHandler( void );
|
||||
#else
|
||||
void UART0_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void UART1_IRQHandler( void );
|
||||
#else
|
||||
void UART1_IRQHandler( void );
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Local functions.
|
||||
*/
|
||||
static void MSS_UART_isr( mss_uart_instance_t * this_uart );
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*/
|
||||
mss_uart_instance_t g_mss_uart0;
|
||||
mss_uart_instance_t g_mss_uart1;
|
||||
|
||||
/***************************************************************************//**
|
||||
* UART_init.
|
||||
* Initialises the UART with default configuration.
|
||||
*/
|
||||
void
|
||||
MSS_UART_init
|
||||
(
|
||||
mss_uart_instance_t* this_uart,
|
||||
uint32_t baud_rate,
|
||||
uint8_t line_config
|
||||
)
|
||||
{
|
||||
uint16_t baud_value;
|
||||
uint32_t pclk_freq;
|
||||
|
||||
/* The driver expects g_mss_uart0 and g_mss_uart1 to be the only
|
||||
* mss_uart_instance_t instances used to identfy UART0 and UART1. */
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
/* Force the value of the CMSIS global variables holding the various system
|
||||
* clock frequencies to be updated. */
|
||||
SystemCoreClockUpdate();
|
||||
|
||||
if ( this_uart == &g_mss_uart0 )
|
||||
{
|
||||
this_uart->hw_reg = UART0;
|
||||
this_uart->hw_reg_bit = UART0_BITBAND;
|
||||
this_uart->irqn = UART0_IRQn;
|
||||
|
||||
pclk_freq = g_FrequencyPCLK0;
|
||||
|
||||
/* reset UART0 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_UART0_SOFTRESET_MASK;
|
||||
/* Clear any previously pended UART0 interrupt */
|
||||
NVIC_ClearPendingIRQ( UART0_IRQn );
|
||||
/* Take UART0 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_UART0_SOFTRESET_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_uart->hw_reg = UART1;
|
||||
this_uart->hw_reg_bit = UART1_BITBAND;
|
||||
this_uart->irqn = UART1_IRQn;
|
||||
|
||||
pclk_freq = g_FrequencyPCLK1;
|
||||
|
||||
/* Reset UART1 */
|
||||
SYSREG->SOFT_RST_CR |= SYSREG_UART1_SOFTRESET_MASK;
|
||||
/* Clear any previously pended UART1 interrupt */
|
||||
NVIC_ClearPendingIRQ( UART1_IRQn );
|
||||
/* Take UART1 out of reset. */
|
||||
SYSREG->SOFT_RST_CR &= ~SYSREG_UART1_SOFTRESET_MASK;
|
||||
}
|
||||
|
||||
/* disable interrupts */
|
||||
this_uart->hw_reg->IER = 0U;
|
||||
|
||||
/*
|
||||
* Compute baud value based on requested baud rate and PCLK frequency.
|
||||
* The baud value is computed using the following equation:
|
||||
* baud_value = PCLK_Frequency / (baud_rate * 16)
|
||||
* The baud value is rounded up or down depending on what would be the remainder
|
||||
* of the divide by 16 operation.
|
||||
*/
|
||||
baud_value = (uint16_t)(pclk_freq / baud_rate);
|
||||
if ( baud_value & 0x00000008U )
|
||||
{
|
||||
/* remainder above 0.5 */
|
||||
baud_value = (baud_value >> 4U) + 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* remainder below 0.5 */
|
||||
baud_value = (baud_value >> 4U);
|
||||
}
|
||||
|
||||
/* set divisor latch */
|
||||
this_uart->hw_reg_bit->LCR_DLAB = (uint32_t)1;
|
||||
|
||||
/* msb of baud value */
|
||||
this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8);
|
||||
/* lsb of baud value */
|
||||
this_uart->hw_reg->DLR = (uint8_t)baud_value;
|
||||
|
||||
/* reset divisor latch */
|
||||
this_uart->hw_reg_bit->LCR_DLAB = (uint32_t)0;
|
||||
|
||||
/* set the line control register (bit length, stop bits, parity) */
|
||||
this_uart->hw_reg->LCR = line_config;
|
||||
|
||||
/* FIFO configuration */
|
||||
this_uart->hw_reg->FCR = (uint8_t)MSS_UART_FIFO_SINGLE_BYTE;
|
||||
|
||||
/* disable loopback */
|
||||
this_uart->hw_reg_bit->MCR_LOOP = (uint32_t)0;
|
||||
|
||||
/* Instance setup */
|
||||
this_uart->tx_buff_size = TX_COMPLETE;
|
||||
this_uart->tx_buffer = (const uint8_t *)0;
|
||||
this_uart->tx_idx = 0U;
|
||||
|
||||
this_uart->rx_handler = (mss_uart_rx_handler_t)0;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_polled_tx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * pbuff,
|
||||
uint32_t tx_size
|
||||
)
|
||||
{
|
||||
uint32_t char_idx;
|
||||
uint32_t status;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
for ( char_idx = 0U; char_idx < tx_size; char_idx++ )
|
||||
{
|
||||
/* Wait for UART to become ready to transmit. */
|
||||
do {
|
||||
status = this_uart->hw_reg_bit->LSR_THRE;
|
||||
} while ( (status & TX_READY) == 0U );
|
||||
/* Send next character in the buffer. */
|
||||
this_uart->hw_reg->THR = pbuff[char_idx];
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_polled_tx_string
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * p_sz_string
|
||||
)
|
||||
{
|
||||
uint32_t char_idx;
|
||||
uint32_t status;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
char_idx = 0U;
|
||||
|
||||
while ( p_sz_string[char_idx] != 0U )
|
||||
{
|
||||
/* Wait for UART to become ready to transmit. */
|
||||
do {
|
||||
status = this_uart->hw_reg_bit->LSR_THRE;
|
||||
} while ( (status & TX_READY) == 0U);
|
||||
/* Send next character in the buffer. */
|
||||
this_uart->hw_reg->THR = p_sz_string[char_idx];
|
||||
++char_idx;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_irq_tx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * pbuff,
|
||||
uint32_t tx_size
|
||||
)
|
||||
{
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
if ( tx_size > 0U )
|
||||
{
|
||||
/*Initialise the transmit info for the UART instance with the arguments.*/
|
||||
this_uart->tx_buffer = pbuff;
|
||||
this_uart->tx_buff_size = tx_size;
|
||||
this_uart->tx_idx = (uint16_t)0;
|
||||
|
||||
/* enables TX interrupt */
|
||||
this_uart->hw_reg_bit->IER_ETBEI = (uint32_t)1;
|
||||
|
||||
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
|
||||
NVIC_EnableIRQ( this_uart->irqn );
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
int8_t
|
||||
MSS_UART_tx_complete
|
||||
(
|
||||
mss_uart_instance_t * this_uart
|
||||
)
|
||||
{
|
||||
int8_t ret_value = 0;
|
||||
uint32_t transmit_empty = this_uart->hw_reg_bit->LSR_TEMT;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
if ( ( TX_COMPLETE == this_uart->tx_buff_size ) && transmit_empty )
|
||||
{
|
||||
ret_value = 1;
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
size_t
|
||||
MSS_UART_get_rx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
uint8_t * rx_buff,
|
||||
size_t buff_size
|
||||
)
|
||||
{
|
||||
size_t rx_size = 0U;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
while (( this_uart->hw_reg_bit->LSR_DR != 0U) && ( rx_size < buff_size ) )
|
||||
{
|
||||
rx_buff[rx_size] = this_uart->hw_reg->RBR;
|
||||
++rx_size;
|
||||
}
|
||||
|
||||
return rx_size;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Interrupt service routine triggered by the Transmitter Holding Register
|
||||
* Empty (THRE) interrupt or Received Data Available (RDA).
|
||||
* On THRE irq this routine will transmit the data from the transmit buffer.
|
||||
* When all bytes are transmitted, this routine disables the THRE interrupt
|
||||
* and resets the transmit counter.
|
||||
* On RDA irq this routine will call the user's receive handler routine previously
|
||||
* registered with the UART driver through a call to UART_set_rx_handler().
|
||||
*/
|
||||
static void
|
||||
MSS_UART_isr
|
||||
(
|
||||
mss_uart_instance_t * this_uart
|
||||
)
|
||||
{
|
||||
uint8_t iirf;
|
||||
uint32_t tx_empty;
|
||||
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
iirf = this_uart->hw_reg->IIR & IIRF_MASK;
|
||||
|
||||
switch ( iirf )
|
||||
{
|
||||
case IIRF_MODEM_STATUS:
|
||||
break;
|
||||
|
||||
case IIRF_THRE: /* Transmitter Holding Register Empty */
|
||||
tx_empty = this_uart->hw_reg_bit->LSR_TEMT;
|
||||
|
||||
if ( tx_empty )
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t fill_size = TX_FIFO_SIZE;
|
||||
uint32_t tx_remain = this_uart->tx_buff_size - this_uart->tx_idx;
|
||||
if ( tx_remain < TX_FIFO_SIZE )
|
||||
{
|
||||
fill_size = tx_remain;
|
||||
}
|
||||
/* Fill up FIFO */
|
||||
for ( i = 0U; i < fill_size; ++i )
|
||||
{
|
||||
this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx];
|
||||
++this_uart->tx_idx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx];
|
||||
++this_uart->tx_idx;
|
||||
}
|
||||
|
||||
if ( this_uart->tx_idx == this_uart->tx_buff_size )
|
||||
{
|
||||
this_uart->tx_buff_size = TX_COMPLETE;
|
||||
/* disables TX interrupt */
|
||||
this_uart->hw_reg_bit->IER_ETBEI = 0U;
|
||||
}
|
||||
break;
|
||||
|
||||
case IIRF_RX_DATA: /* Received Data Available */
|
||||
case IIRF_DATA_TIMEOUT:
|
||||
if (this_uart->rx_handler != 0)
|
||||
{
|
||||
(*(this_uart->rx_handler))();
|
||||
}
|
||||
break;
|
||||
|
||||
case IIRF_RX_LINE_STATUS:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Disable other interrupts */
|
||||
this_uart->hw_reg_bit->IER_ELSI = 0U;
|
||||
this_uart->hw_reg_bit->IER_EDSSI = 0U;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_set_rx_handler
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
mss_uart_rx_handler_t handler,
|
||||
mss_uart_rx_trig_level_t trigger_level
|
||||
)
|
||||
{
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
this_uart->rx_handler = handler;
|
||||
|
||||
/* Set the receive interrupt trigger level. */
|
||||
this_uart->hw_reg->FCR = (this_uart->hw_reg->FCR & (uint8_t)(~((uint8_t)FCR_TRIG_LEVEL_MASK))) | (uint8_t)trigger_level;
|
||||
|
||||
/* Enable receive interrupt. */
|
||||
this_uart->hw_reg_bit->IER_ERBFI = 1U;
|
||||
|
||||
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
|
||||
NVIC_EnableIRQ( this_uart->irqn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* See mss_uart.h for details of how to use this function.
|
||||
*/
|
||||
void
|
||||
MSS_UART_set_loopback
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
mss_uart_loopback_t loopback
|
||||
)
|
||||
{
|
||||
ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
|
||||
|
||||
if ( loopback == MSS_UART_LOOPBACK_OFF )
|
||||
{
|
||||
this_uart->hw_reg_bit->MCR_LOOP = 0U;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_uart->hw_reg_bit->MCR_LOOP = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* UART0 interrupt service routine.
|
||||
* UART0_IRQHandler is included within the Cortex-M3 vector table as part of the
|
||||
* Fusion 2 CMSIS.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void UART0_IRQHandler( void )
|
||||
#else
|
||||
void UART0_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
MSS_UART_isr( &g_mss_uart0 );
|
||||
NVIC_ClearPendingIRQ( UART0_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* UART1 interrupt service routine.
|
||||
* UART2_IRQHandler is included within the Cortex-M3 vector table as part of the
|
||||
* Fusion 2 CMSIS.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((__interrupt__)) void UART1_IRQHandler( void )
|
||||
#else
|
||||
void UART1_IRQHandler( void )
|
||||
#endif
|
||||
{
|
||||
MSS_UART_isr( &g_mss_uart1 );
|
||||
NVIC_ClearPendingIRQ( UART1_IRQn );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,626 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2007 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion Microcontroller Subsystem UART bare metal software driver public API.
|
||||
*
|
||||
* SVN $Revision: 1942 $
|
||||
* SVN $Date: 2009-12-22 17:48:07 +0000 (Tue, 22 Dec 2009) $
|
||||
*/
|
||||
/*=========================================================================*//**
|
||||
@mainpage SmartFusion MSS UART Bare Metal Driver.
|
||||
|
||||
@section intro_sec Introduction
|
||||
The SmartFusion MicroController Subsystem (MSS) includes two UART peripherals
|
||||
for serial communications.
|
||||
This driver provides a set of functions for controlling the MSS UARTs as part
|
||||
of a bare metal system where no operating system is available. These drivers
|
||||
can be adapted for use as part of an operating system but the implementation
|
||||
of the adaptation layer between this driver and the operating system's driver
|
||||
model is outside the scope of this driver.
|
||||
|
||||
@section hw_dependencies Hardware Flow Dependencies
|
||||
The configuration of all features of the MSS UARTs is covered by this driver
|
||||
with the exception of the SmartFusion IOMUX configuration. SmartFusion allows
|
||||
multiple non-concurrent uses of some external pins through IOMUX configuration.
|
||||
This feature allows optimization of external pin usage by assigning external
|
||||
pins for use by either the microcontroller subsystem or the FPGA fabric. The
|
||||
MSS UARTs serial signals are routed through IOMUXes to the SmartFusion device
|
||||
external pins. These IOMUXes are configured automatically by the MSS
|
||||
configurator tool in the hardware flow correctly when the MSS UARTs are enabled
|
||||
in that tool. You must ensure that the MSS UARTs are enabled by the MSS
|
||||
configurator tool in the hardware flow; otherwise the serial inputs and outputs
|
||||
will not be connected to the chip's external pins. For more information on
|
||||
IOMUX, refer to the IOMUX section of the SmartFusion Datasheet.
|
||||
The base address, register addresses and interrupt number assignment for the MSS
|
||||
UART blocks are defined as constants in the SmartFusion CMSIS-PAL You must ensure
|
||||
that the SmartFusion CMSIS-PAL is either included in the software tool chain used
|
||||
to build your project or is included in your project.
|
||||
|
||||
|
||||
@section theory_op Theory of Operation
|
||||
The MSS UART driver uses the SmartFusion "Cortex Microcontroler Software
|
||||
Interface Standard - Peripheral Access Layer" (CMSIS-PAL) to access hadware
|
||||
registers. You must ensure that the SmartFusion CMSIS-PAL is either included
|
||||
in the software toolchain used to build your project or is included in your
|
||||
project. The most up to date SmartFusion CMSIS-PAL files can be obtained using
|
||||
the Actel Firmware Catalog.
|
||||
|
||||
The MSS UART driver functions are logically grouped into three groups:
|
||||
- Initialization functions
|
||||
- Polled transmit and receive functions
|
||||
- Interrupt driven transmit and receive functions
|
||||
|
||||
The MSS UART driver is initialized through a call to the UART_init() function.
|
||||
This function takes the UART's configuration as parameters. The UART_init()
|
||||
function must be called before any other UART driver functions can be called.
|
||||
The first parameter of the UART_init() function is a pointer to one of two
|
||||
global data structures used to store state information for each UART driver.
|
||||
A pointer to these data structures is also used as first parameter to any of
|
||||
the driver functions to identify which UART will be used by the called
|
||||
function. The name of these two data structures are g_mss_uart0 and
|
||||
g_mss_uart1. Therefore any call to a MSS UART function should be of the form
|
||||
UART_function_name( &g_mss_uart0, ... ) or UART_function_name( &g_mss_uart1, ... ).
|
||||
The two SmartFusion MSS UARTs can also be configured to loop back to each
|
||||
other using the MSS_set_loopback() function for debugging purposes.
|
||||
|
||||
Polled operations where the processor constantly poll the UART registers state
|
||||
in order to control data transmit or data receive is performed using functions:
|
||||
- MSS_UART_polled_tx()
|
||||
- MSS_UART_get_rx()
|
||||
|
||||
Interrupt driven operations where the processor sets up transmit or receive
|
||||
then returns to performing some other operation until an interrupts occurs
|
||||
indicating that its attention is required is performed using functions:
|
||||
- MSS_UART_irq_tx()
|
||||
- MSS_UART_tx_complete()
|
||||
- MSS_UART_set_rx_handler()
|
||||
- MSS_UART_get_rx()
|
||||
Interrupt driven transmit is initiated by a call to MSS_UART_irq_tx() specifying
|
||||
the block of data to transmit. The processor can then perform some other
|
||||
operation and later inquire whether transmit has completed by calling the
|
||||
MSS_UART_tx_complete() function.
|
||||
Interrupt driven receive is performed by first registering a receive handler
|
||||
function that will be called by the driver whenever receive data is available.
|
||||
This receive handler function in turns calls the MSS_UART_get_rx() function to
|
||||
actually read the received data.
|
||||
|
||||
*//*=========================================================================*/
|
||||
#ifndef __MSS_UART_H_
|
||||
#define __MSS_UART_H_ 1
|
||||
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
Baud rates.
|
||||
The following definitions are used to specify standard baud rates as a
|
||||
parameter to the MSS_UART_init() function.
|
||||
*/
|
||||
#define MSS_UART_110_BAUD 110
|
||||
#define MSS_UART_300_BAUD 300
|
||||
#define MSS_UART_1200_BAUD 1200
|
||||
#define MSS_UART_2400_BAUD 2400
|
||||
#define MSS_UART_4800_BAUD 4800
|
||||
#define MSS_UART_9600_BAUD 9600
|
||||
#define MSS_UART_19200_BAUD 19200
|
||||
#define MSS_UART_38400_BAUD 38400
|
||||
#define MSS_UART_57600_BAUD 57600
|
||||
#define MSS_UART_115200_BAUD 115200
|
||||
#define MSS_UART_230400_BAUD 230400
|
||||
#define MSS_UART_460800_BAUD 460800
|
||||
#define MSS_UART_921600_BAUD 921600
|
||||
|
||||
/***************************************************************************//**
|
||||
Data bits length values.
|
||||
|
||||
The following defines are used to build the value of the MSS_UART_init()
|
||||
function line_config parameter.
|
||||
*/
|
||||
#define MSS_UART_DATA_5_BITS 0x00
|
||||
#define MSS_UART_DATA_6_BITS 0x01
|
||||
#define MSS_UART_DATA_7_BITS 0x02
|
||||
#define MSS_UART_DATA_8_BITS 0x03
|
||||
|
||||
/***************************************************************************//**
|
||||
Parity values
|
||||
The following defines are used to build the value of the MSS_UART_init()
|
||||
function line_config parameter.
|
||||
*/
|
||||
#define MSS_UART_NO_PARITY 0x00
|
||||
#define MSS_UART_ODD_PARITY 0x08
|
||||
#define MSS_UART_EVEN_PARITY 0x18
|
||||
#define MSS_UART_STICK_PARITY_0 0x38
|
||||
#define MSS_UART_STICK_PARITY_1 0x28
|
||||
|
||||
/***************************************************************************//**
|
||||
Stop bit values
|
||||
The following defines are used to build the value of the MSS_UART_init()
|
||||
function line_config parameter.
|
||||
*/
|
||||
#define MSS_UART_ONE_STOP_BIT 0x00
|
||||
#define MSS_UART_ONEHALF_STOP_BIT 0x04
|
||||
#define MSS_UART_TWO_STOP_BITS 0x04
|
||||
|
||||
/***************************************************************************//**
|
||||
FIFO trigger sizes
|
||||
This enumeration specifies the number of bytes that must be received before a
|
||||
receive interrupt is generated. This enumeration provides the allowed values for
|
||||
the MSS_UART_set_rx_handler() function trigger_level parameter.
|
||||
*/
|
||||
typedef enum __mss_uart_rx_trig_level_t {
|
||||
MSS_UART_FIFO_SINGLE_BYTE = 0x00,
|
||||
MSS_UART_FIFO_FOUR_BYTES = 0x40,
|
||||
MSS_UART_FIFO_EIGHT_BYTES = 0x80,
|
||||
MSS_UART_FIFO_FOURTEEN_BYTES = 0xC0
|
||||
} mss_uart_rx_trig_level_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
Loopback.
|
||||
This enumeration is used as parameter to function MSS_UART_set_loopback(). It
|
||||
specifies the loopback configuration of the UARTs. Using MSS_UART_LOOPBACK_ON
|
||||
as parameter to function MSS_UART_set_loopback() will set up the UART to locally
|
||||
loopback its Tx and Rx lines.
|
||||
*/
|
||||
typedef enum __mss_uart_loopback_t {
|
||||
MSS_UART_LOOPBACK_OFF = 0,
|
||||
MSS_UART_LOOPBACK_ON = 1
|
||||
} mss_uart_loopback_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
Receive handler prototype.
|
||||
This typedef specifies the prototype of functions that can be registered with
|
||||
this driver as receive handler functions.
|
||||
*/
|
||||
typedef void (*mss_uart_rx_handler_t)(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
mss_uart_instance_t.
|
||||
|
||||
There is one instance of this structure for each instance of the Microcontroller
|
||||
Subsystem's UARTs. Instances of this structure are used to identify a specific
|
||||
UART. A pointer to an instance of the mss_uart_instance_t structure is passed
|
||||
as the first parameter to MSS UART driver functions to identify which UART
|
||||
should perform the requested operation.
|
||||
*/
|
||||
typedef struct {
|
||||
/* CMSIS related defines identifying the UART hardware. */
|
||||
UART_TypeDef * hw_reg; /*!< Pointer to UART registers. */
|
||||
UART_BitBand_TypeDef * hw_reg_bit; /*!< Pointer to UART registers bit band area. */
|
||||
IRQn_Type irqn; /*!< UART's Cortex-M3 NVIC interrupt number. */
|
||||
|
||||
/* transmit related info (used with interrupt driven trnasmit): */
|
||||
const uint8_t * tx_buffer; /*!< Pointer to transmit buffer. */
|
||||
uint32_t tx_buff_size; /*!< Transmit buffer size. */
|
||||
uint32_t tx_idx; /*!< Index within trnamit buffer of next byte to transmit.*/
|
||||
|
||||
/* receive interrupt handler:*/
|
||||
mss_uart_rx_handler_t rx_handler; /*!< Pointer to user registered received handler. */
|
||||
} mss_uart_instance_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
This instance of mss_uart_instance_t holds all data related to the operations
|
||||
performed by UART0. A pointer to g_mss_uart0 is passed as the first parameter
|
||||
to MSS UART driver functions to indicate that UART0 should perform the requested
|
||||
operation.
|
||||
*/
|
||||
extern mss_uart_instance_t g_mss_uart0;
|
||||
|
||||
/***************************************************************************//**
|
||||
This instance of mss_uart_instance_t holds all data related to the operations
|
||||
performed by UART1. A pointer to g_mss_uart1 is passed as the first parameter
|
||||
to MSS UART driver functions to indicate that UART1 should perform the requested
|
||||
operation.
|
||||
*/
|
||||
extern mss_uart_instance_t g_mss_uart1;
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_init() function initializes and configures one of the SmartFusion
|
||||
MSS UARTs with the configuration passed as a parameter. The configuration
|
||||
parameters are the baud_rate which is used to generate the baud value and the
|
||||
line_config which is used to specify the line configuration (bit length, stop
|
||||
bits and parity).
|
||||
|
||||
Example:
|
||||
@code
|
||||
#include "mss_uart.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
MSS_UART_init
|
||||
(
|
||||
&g_mss_uart0,
|
||||
MSS_UART_57600_BAUD,
|
||||
MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT
|
||||
);
|
||||
return(0);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block to be initialized. There are two
|
||||
such data structures, g_mss_uart0 and g_mss_uart1, associated with MSS UART0
|
||||
and MSS UART1 respectively. This parameter must point to either the
|
||||
g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
|
||||
@param baud_rate
|
||||
The baud_rate parameter specifies the baud rate. It can be specified for
|
||||
common baud rates' using the following defines:
|
||||
- MSS_UART_110_BAUD
|
||||
- MSS_UART_300_BAUD
|
||||
- MSS_UART_1200_BAUD
|
||||
- MSS_UART_2400_BAUD
|
||||
- MSS_UART_4800_BAUD
|
||||
- MSS_UART_9600_BAUD
|
||||
- MSS_UART_19200_BAUD
|
||||
- MSS_UART_38400_BAUD
|
||||
- MSS_UART_57600_BAUD
|
||||
- MSS_UART_115200_BAUD
|
||||
- MSS_UART_230400_BAUD
|
||||
- MSS_UART_460800_BAUD
|
||||
- MSS_UART_921600_BAUD
|
||||
Alternatively, any non standard baud rate can be specified by simply passing
|
||||
the actual required baud rate as value for this parameter.
|
||||
|
||||
@param line_config
|
||||
The line_config parameter is the line configuration specifying the bit length,
|
||||
number of stop bits and parity settings. This is a logical OR of one of the
|
||||
following to specify the transmit/receive data bit length:
|
||||
- MSS_UART_DATA_5_BITS
|
||||
- MSS_UART_DATA_6_BITS,
|
||||
- MSS_UART_DATA_7_BITS
|
||||
- MSS_UART_DATA_8_BITS
|
||||
with one of the following to specify the parity setting:
|
||||
- MSS_UART_NO_PARITY
|
||||
- MSS_UART_EVEN_PARITY
|
||||
- MSS_UART_ODD_PARITY
|
||||
- MSS_UART_STICK_PARITY_0
|
||||
- MSS_UART_STICK_PARITY_1
|
||||
with one of the following to specify the number of stop bits:
|
||||
- MSS_UART_ONE_STOP_BIT
|
||||
- MSS_UART_ONEHALF_STOP_BIT
|
||||
- MSS_UART_TWO_STOP_BITS
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_init
|
||||
(
|
||||
mss_uart_instance_t* this_uart,
|
||||
uint32_t baud_rate,
|
||||
uint8_t line_config
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The function MSS_UART_polled_tx() is used to transmit data. It transfers the
|
||||
contents of the transmitter data buffer, passed as a function parameter, into
|
||||
the UART's hardware transmitter FIFO. It returns when the full content of the
|
||||
transmit data buffer has been transferred to the UART's transmit FIFO.
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param pbuff
|
||||
The pbuff parameter is a pointer to a buffer containing the data to be
|
||||
transmitted.
|
||||
|
||||
@param tx_size
|
||||
The tx_size parameter specifies the size, in bytes, of the data to be
|
||||
transmitted.
|
||||
|
||||
@return This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_polled_tx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * pbuff,
|
||||
uint32_t tx_size
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The function MSS_UART_polled_tx_string() is used to transmit a zero-terminated
|
||||
string. It transfers the text found starting at the address pointed to by
|
||||
p_sz_string into the UART's hardware transmitter FIFO. It returns when the
|
||||
complete string has been transferred to the UART's transmit FIFO.
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param p_sz_string
|
||||
The p_sz_string parameter is a pointer to a buffer containing the
|
||||
zero-terminated string to be transmitted.
|
||||
|
||||
@return This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_polled_tx_string
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * p_sz_string
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
The function MSS_UART_irq_tx() is used to initiate interrupt driven transmit. It
|
||||
returns immediately after making a note of the transmit buffer location and
|
||||
enabling transmit interrupts both at the UART and Cortex-M3 NVIC level.
|
||||
This function takes a pointer to a memory buffer containing the data to
|
||||
transmit as parameter. The memory buffer specified through this pointer
|
||||
should remain allocated and contain the data to transmit until the transmit
|
||||
completion has been detected through calls to function MSS_UART_tx_complete().
|
||||
NOTE: The MSS_UART_irq_tx() function also enables the Transmitter Holding
|
||||
Register Empty (THRE) interrupt and the UART instance interrupt in the
|
||||
Cortex-M3 NVIC as part of its implementation.
|
||||
|
||||
Example:
|
||||
@code
|
||||
#include "mss_uart.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uint8_t tx_buff[10] = "abcdefghi";
|
||||
MSS_UART_init( &g_mss_uart0, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
|
||||
MSS_UART_irq_tx( &g_mss_uart0, tx_buff, sizeof(tx_buff));
|
||||
while ( 0 == MSS_UART_tx_complete( &g_mss_uart0 ) )
|
||||
{
|
||||
;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param pbuff
|
||||
The pbuff parameter is a pointer to a buffer containing the data to be
|
||||
transmitted.
|
||||
|
||||
@param tx_size
|
||||
The tx_size parameter specifies the size, in bytes, of the data to be
|
||||
transmitted.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_irq_tx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
const uint8_t * pbuff,
|
||||
uint32_t tx_size
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_tx_complete() function is used to find out if interrupt driven
|
||||
transmit previously initiated through a call to MSS_UART_irq_tx() is complete.
|
||||
This is typically used to find out when it is safe to reuse or release the
|
||||
memory buffer holding transmit data.
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@return
|
||||
This function return a non-zero value if transmit has completed, otherwise
|
||||
it returns zero.
|
||||
|
||||
Example:
|
||||
See the MSS_UART_irq_tx() function for an example that uses the
|
||||
MSS_UART_tx_complete() function.
|
||||
*/
|
||||
int8_t
|
||||
MSS_UART_tx_complete
|
||||
(
|
||||
mss_uart_instance_t * this_uart
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_get_rx() function is used to read the content of a UART's receive
|
||||
FIFO. It can be used in polled mode where it is called at regular interval
|
||||
to find out if any data has been received or in interrupt driven mode where
|
||||
it is called as part of a receive handler called by the driver as a result of
|
||||
data being received. This function is non-blocking and will return 0
|
||||
immediately if no data has been received.
|
||||
NOTE: In interrupt driven mode you should call the MSS_UART_get_rx() function
|
||||
as part of the receive handler function that you register with the MSS UART
|
||||
driver through a call to MSS_UART_set_rx_handler().
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param rx_buff
|
||||
The rx_buff parameter is a pointer to a buffer where the received data will
|
||||
be copied.
|
||||
|
||||
@param buff_size
|
||||
The buff_size parameter specifies the size of the receive buffer in bytes.
|
||||
|
||||
@return
|
||||
This function return the number of bytes that were copied into the rx_buff
|
||||
buffer. It returns 0 if no data has been received.
|
||||
|
||||
Polled mode example:
|
||||
@code
|
||||
int main( void )
|
||||
{
|
||||
uint8_t rx_buff[RX_BUFF_SIZE];
|
||||
uint32_t rx_idx = 0;
|
||||
|
||||
MSS_UART_init( &g_mss_uart0, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
rx_size = MSS_UART_get_rx( &g_mss_uart0, rx_buff, sizeof(rx_buff) );
|
||||
if (rx_size > 0)
|
||||
{
|
||||
process_rx_data( rx_buff, rx_size );
|
||||
}
|
||||
task_a();
|
||||
task_b();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
|
||||
Interrupt driven example:
|
||||
@code
|
||||
int main( void )
|
||||
{
|
||||
MSS_UART_init( &g_mss_uart1, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
|
||||
MSS_UART_set_rx_handler( &g_mss_uart1, uart1_rx_handler, MSS_UART_FIFO_SINGLE_BYTE );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
task_a();
|
||||
task_b();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uart1_rx_handler( void )
|
||||
{
|
||||
uint8_t rx_buff[RX_BUFF_SIZE];
|
||||
uint32_t rx_idx = 0;
|
||||
rx_size = MSS_UART_get_rx( &g_mss_uart1, rx_buff, sizeof(rx_buff) );
|
||||
process_rx_data( rx_buff, rx_size );
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
size_t
|
||||
MSS_UART_get_rx
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
uint8_t * rx_buff,
|
||||
size_t buff_size
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_set_rx_handler() function is used to register a receive handler
|
||||
function which will be called by the driver when a UART Received Data Available
|
||||
(RDA) interrupt occurs. You must create and register the handler function to
|
||||
suit your application. The MSS_UART_set_rx_handler() function also enables the UART
|
||||
Received Data Available interrupt and the UART instance interrupt in the
|
||||
Cortex-M3 NVIC as part of its implementation.
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param handler
|
||||
The handler parameter is a pointer to a receive handler function provided
|
||||
by your application which will be called as a result of a UART Received
|
||||
Data Available interrupt.
|
||||
|
||||
@param trigger_level
|
||||
The trigger_level parameter is the receive FIFO trigger level. This specifies
|
||||
the number of bytes that must be received before the UART triggers a Received
|
||||
Data Available interrupt.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
|
||||
Example:
|
||||
@code
|
||||
#include "mss_uart.h"
|
||||
|
||||
#define RX_BUFF_SIZE 64
|
||||
|
||||
uint8_t g_rx_buff[RX_BUFF_SIZE];
|
||||
|
||||
void uart0_rx_handler( void )
|
||||
{
|
||||
MSS_UART_get_rx( &g_mss_uart, &g_rx_buff[g_rx_idx], sizeof(g_rx_buff) );
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
MSS_UART_init( &g_mss_uart0, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT );
|
||||
MSS_UART_set_rx_handler( &g_mss_uart0, uart0_rx_handler, MSS_UART_FIFO_SINGLE_BYTE );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
void
|
||||
MSS_UART_set_rx_handler
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
mss_uart_rx_handler_t handler,
|
||||
mss_uart_rx_trig_level_t trigger_level
|
||||
);
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_UART_set_loopback() function is used to locally loopback the Tx and Rx
|
||||
lines of a UART.
|
||||
This is not to be confused with the loopback of UART0 to UART1 which can be
|
||||
achieved through the microcontroller subsystem's system registers
|
||||
|
||||
@param this_uart
|
||||
The this_uart parameter is a pointer to an mss_uart_instance_t structure
|
||||
identifying the MSS UART hardware block that will perform the requested
|
||||
function. There are two such data structures, g_mss_uart0 and g_mss_uart1,
|
||||
associated with MSS UART0 and MSS UART1. This parameter must point to either
|
||||
the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART
|
||||
driver.
|
||||
|
||||
@param loopback
|
||||
The loopback parameter indicates whether or not the UART's transmit and receive lines
|
||||
should be looped back. Allowed values are:
|
||||
- MSS_UART_LOOPBACK_ON
|
||||
- MSS_UART_LOOPBACK_OFF
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
void
|
||||
MSS_UART_set_loopback
|
||||
(
|
||||
mss_uart_instance_t * this_uart,
|
||||
mss_uart_loopback_t loopback
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MSS_UART_H_ */
|
|
@ -0,0 +1,427 @@
|
|||
/*******************************************************************************
|
||||
* (c) Copyright 2009 Actel Corporation. All rights reserved.
|
||||
*
|
||||
* SmartFusion Microcontroller Subsystem (MSS) Watchdog bare metal software
|
||||
* driver.
|
||||
*
|
||||
* SVN $Revision: 1888 $
|
||||
* SVN $Date: 2009-12-18 10:58:42 +0000 (Fri, 18 Dec 2009) $
|
||||
*/
|
||||
/*=========================================================================*//**
|
||||
@section intro_sec Introduction
|
||||
The SmartFusion microcontroller subsystem (MSS) includes a watchdog timer used
|
||||
to detect system lockups.
|
||||
This driver provides a set of functions for controlling the MSS watchdog as
|
||||
part of a bare metal system where no operating system is available. These
|
||||
drivers can be adapted for use as part of an operating system but the
|
||||
implementation of the adaptation layer between this driver and the operating
|
||||
system's driver model is outside the scope of this driver.
|
||||
|
||||
@section hw_dependencies Hardware Flow Dependencies
|
||||
The configuration of all features of the MSS watchdog is covered by this
|
||||
driver. There are no dependencies on the hardware flow for configuring the
|
||||
SmartFusion MSS watchdog timer.
|
||||
|
||||
@section theory_op Theory of Operation
|
||||
The watchdog driver uses the SmartFusion "Cortex Microcontroler Software
|
||||
Interface Standard - Peripheral Access Layer" (CMSIS-PAL) to access hadware
|
||||
registers. You must ensure that the SmartFusion CMSIS-PAL is either included
|
||||
in the software toolchain used to build your project or is included in your
|
||||
project. The most up-to-date SmartFusion CMSIS-PAL files can be obtained using
|
||||
the Actel Firmware Catalog.
|
||||
|
||||
The watchdog driver functions are grouped into the following categories:
|
||||
- Initialization and cnfiguration
|
||||
- Reading the watchdog timer current value and status
|
||||
- Refreshing the watchdog timer value
|
||||
- Time-out and wake-up interrupts control
|
||||
|
||||
The watchdog driver is initialized and configured through a call to the
|
||||
MSS_WD_init() function. The parameters passed to MSS_WD_init() function
|
||||
specify the watchdog timer configuration. The configuration parameters include
|
||||
the value that will be reloaded into the watchdog timer down counter every
|
||||
time the watchdog is refreshed. Also included as part of the configuration
|
||||
parameters is the optional allowed refresh window. The allowed refresh window
|
||||
specifies the maximum allowed current value of the watchdog timer at the time
|
||||
of the watchdog is relaoded. Attempting to reload the watchdog timer when its
|
||||
value is larger than the allowed refresh window will cause a reset or
|
||||
interrupt depending on the watchdog configuration. The allowed refresh window
|
||||
can be disabled by specifying an allowed refesh window equal or higher than
|
||||
the watchdog reload value.
|
||||
The MSS_WD_init() function must be called before any other watchdog driver
|
||||
functions can be called with the exception of the MSS_WD_disable() function.
|
||||
|
||||
The watchdog timer can be disabled using the MSS_WD_disable() function. Once
|
||||
disabled, the watchdog timer can only be reenabled by a power-on reset.
|
||||
|
||||
The watchdog timer current value can be read using the MSS_WD_current_value()
|
||||
function. The watchdog status can be read using the MSS_WD_status() function.
|
||||
These functions are typically required when using the watchdog configured with
|
||||
an allowed refresh window to check if a watchdog reload is currently allowed.
|
||||
|
||||
The watchdog timer value is reloaded using the MSS_WD_reload() function. The
|
||||
value reloaded into the watchdog timer down counter is the value specified as
|
||||
parameter to the MSS_WD_init() function.
|
||||
|
||||
The watchdog timer can generate interrupts instead of resetting the system
|
||||
when its down-counter timer expires. These time-out interrupts are controlled
|
||||
using the following functions:
|
||||
- MSS_WD_enable_timeout_irq
|
||||
- MSS_WD_disable_timeout_irq
|
||||
- MSS_WD_clear_timeout_irq
|
||||
|
||||
The watchdog timer is external to the Cortex-M3 processor core and operates
|
||||
even when the Cortex-M3 is in sleep mode. A wakeup interrupt can be generated
|
||||
by the watchdog timer to wakeup the Cortext-M3 when the watchdog timer value
|
||||
reaches the allowed refresh window while the Cortex-M3 is in sleep mode. The
|
||||
watchdog driver provides the following functions to control wakeup interrupts:
|
||||
- MSS_WD_enable_wakeup_irq
|
||||
- MSS_WD_disable_wakeup_irq
|
||||
- MSS_WD_clear_wakeup_irq
|
||||
|
||||
*//*=========================================================================*/
|
||||
|
||||
#ifndef MSS_WATCHDOG_H_
|
||||
#define MSS_WATCHDOG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../CMSIS/a2fxxxm3.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* The MSS_WDOG_RESET_ON_TIMEOUT_MODE macro is one of the possible values for the
|
||||
* mode parameter of the WD_init() function. It is used to specify that a reset
|
||||
* should occur when the watchdog down counter times out.
|
||||
*/
|
||||
#define MSS_WDOG_RESET_ON_TIMEOUT_MODE (uint32_t)0x00000000U
|
||||
|
||||
/***************************************************************************//**
|
||||
* The MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE macro is one of the possible values for
|
||||
* the mode parameter of function the WD_init() function. It is used to specify
|
||||
* that a time out interrupt should occur when the watchdog down counter expires.
|
||||
*/
|
||||
#define MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE (uint32_t)0x00000004U
|
||||
|
||||
/***************************************************************************//**
|
||||
* The MSS_WDOG_NO_WINDOW macro can be used as the value for the reload_window
|
||||
* parameter of the WD_init() function. It is used to specify that no forbidden
|
||||
* window will exist for the reload of the watchdog down counter.
|
||||
*/
|
||||
#define MSS_WDOG_NO_WINDOW (uint32_t)0xFFFFFFFFU
|
||||
|
||||
/***************************************************************************//**
|
||||
* The MSS_WDOG_CTRL_MODE_BIT_MASK macro is a bit mask specifying the bit used to
|
||||
* set the watchdog's operating mode within the wathcdog's WDOGCONTROL register.
|
||||
*/
|
||||
#define MSS_WDOG_CTRL_MODE_BIT_MASK (uint32_t)0x00000004U
|
||||
|
||||
/***************************************************************************//**
|
||||
* The MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK macro is a bit mask specifying the bit
|
||||
* used to enable the time out interrupt within the watchdog's WDOGCONTROL
|
||||
* register.
|
||||
*/
|
||||
#define MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK (uint32_t)0x00000001U
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WDOG_WAKEUP_IRQ_ENABLE_BIT_MASK macro is a bit mask specifying the bit
|
||||
used to enable the wake up interrupt within the watchdog's WDOGCONTROL
|
||||
register.
|
||||
*/
|
||||
#define MSS_WDOG_WAKEUP_IRQ_ENABLE_BIT_MASK (uint32_t)0x00000002U
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK macro is a bit mask specifying the bit
|
||||
used to clear the time out interrupt within the watchdog's WDOGRIS register.
|
||||
*/
|
||||
#define MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK (uint32_t)0x00000001U
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK macro is a bit mask specifying the bit
|
||||
used to clear the wake up interrupt within the watchdog's WDOGRIS register.
|
||||
*/
|
||||
#define MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK (uint32_t)0x00000002U
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WDOG_REFRESH_KEY macro holds the magic value which will cause a reload
|
||||
of the watchdog's down counter when written to the watchdog's WDOGREFRESH
|
||||
register.
|
||||
*/
|
||||
#define MSS_WDOG_REFRESH_KEY (uint32_t)0xAC15DE42U
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WDOG_DISABLE_KEY macro holds the magic value which will disable the
|
||||
watchdog if written to the watchdog's WDOGENABLE register.
|
||||
*/
|
||||
#define MSS_WDOG_DISABLE_KEY (uint32_t)0x4C6E55FAU
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_init() function initializes and configures the watchdog timer.
|
||||
|
||||
@param load_value
|
||||
The load_value parameter specifies the value that will be loaded into the
|
||||
watchdog's down counter when the reload command is issued through a call to
|
||||
MSS_WD_reload().
|
||||
|
||||
@param reload_window
|
||||
The reload_window parameter specifies the time window during which a reload
|
||||
of the watchdog counter is allowed. A reload of the watchdog counter should
|
||||
only be performed when the watchdog counter value is below the value of the
|
||||
reload_window. Reloading the watchdog down counter value before it has
|
||||
reached the reload_window will result in an interrupt or reset depending on
|
||||
the watchdog's mode.
|
||||
The reload window can be disabled by using WDOG_NO_WINDOW for this parameter.
|
||||
|
||||
@param mode
|
||||
The mode parameter specifies the watchdog's operating mode. It can be either
|
||||
MSS_WDOG_RESET_ON_TIMEOUT_MODE or MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE.
|
||||
MSS_WDOG_RESET_ON_TIMEOUT_MODE: a reset will occur if the watchdog timer
|
||||
expires.
|
||||
MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE: an NMI interrupt will occur if the
|
||||
watchdog timer expires.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
static __INLINE void MSS_WD_init
|
||||
(
|
||||
uint32_t load_value,
|
||||
uint32_t reload_window,
|
||||
uint32_t mode
|
||||
)
|
||||
{
|
||||
/* Disable interrupts. */
|
||||
WATCHDOG->WDOGCONTROL &= ~(MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK | MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK);
|
||||
|
||||
/* Clear any existing interrupts. */
|
||||
WATCHDOG->WDOGRIS = MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK | MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK;
|
||||
|
||||
/* Configure watchdog with new configuration passed as parameter. */
|
||||
WATCHDOG->WDOGMVRP = MSS_WDOG_NO_WINDOW;
|
||||
WATCHDOG->WDOGLOAD = load_value;
|
||||
WATCHDOG->WDOGCONTROL = (WATCHDOG->WDOGCONTROL & ~MSS_WDOG_CTRL_MODE_BIT_MASK) | (mode & MSS_WDOG_CTRL_MODE_BIT_MASK);
|
||||
|
||||
/* Reload watchdog with new load value. */
|
||||
WATCHDOG->WDOGREFRESH = MSS_WDOG_REFRESH_KEY;
|
||||
|
||||
/* Set allowed window. */
|
||||
WATCHDOG->WDOGMVRP = reload_window;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_reload() function causes the watchdog to reload its down counter timer
|
||||
with the load value configured through the call to WD_init(). This function
|
||||
must be called regularly to avoid a system reset.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
static __INLINE void MSS_WD_reload( void )
|
||||
{
|
||||
WATCHDOG->WDOGREFRESH = MSS_WDOG_REFRESH_KEY;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_disable() function disables the watchdog.
|
||||
Please note that the watchdog can only be reenabled as a result of a power-on
|
||||
reset.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
static __INLINE void MSS_WD_disable( void )
|
||||
{
|
||||
WATCHDOG->WDOGENABLE = MSS_WDOG_DISABLE_KEY;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_current_value() function returns the current value of the watchdog's
|
||||
down counter.
|
||||
|
||||
@return
|
||||
This function returns the current value of the watchdog down counter.
|
||||
*/
|
||||
static __INLINE uint32_t MSS_WD_current_value( void )
|
||||
{
|
||||
return WATCHDOG->WDOGVALUE;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_status() function returns the status of the watchdog.
|
||||
|
||||
@return
|
||||
The MSS_WD_status() function returns the status of the watchdog. A value of
|
||||
0 indicates that watchdog counter has reached the forbidden window and that
|
||||
a reload should not be done. A value of 1 indicates that the watchdog counter
|
||||
is within the permitted window and that a reload is allowed.
|
||||
*/
|
||||
static __INLINE uint32_t MSS_WD_status( void )
|
||||
{
|
||||
return WATCHDOG->WDOGSTATUS;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_enable_timeout_irq() function enables the watchdog’s time out
|
||||
interrupt which is connected to the Cortex-M3 NMI interrupt.
|
||||
The NMI_Handler() function will be called when a watchdog time out occurs. You
|
||||
must provide the implementation of the NMI_Handler() function to suit your
|
||||
application.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
|
||||
Example:
|
||||
@code
|
||||
#include "mss_watchdog.h"
|
||||
int main( void )
|
||||
{
|
||||
MSS_WD_init( 0x10000000, MSS_WDOG_NO_WINDOW, MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE );
|
||||
MSS_WD_enable_timeout_irq();
|
||||
for (;;)
|
||||
{
|
||||
main_task();
|
||||
}
|
||||
}
|
||||
|
||||
void NMI_Handler( void )
|
||||
{
|
||||
process_timeout();
|
||||
MSS_WD_clear_timeout_irq();
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
static __INLINE void MSS_WD_enable_timeout_irq( void )
|
||||
{
|
||||
WATCHDOG->WDOGCONTROL |= MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The WD_disable_timeout_irq() function disables the generation of the NMI
|
||||
interrupt when the watchdog times out.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
static __INLINE void MSS_WD_disable_timeout_irq( void )
|
||||
{
|
||||
WATCHDOG->WDOGCONTROL &= ~MSS_WDOG_TIMEOUT_IRQ_ENABLE_BIT_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_enable_wakeup_irq() function enables the SmartFusion wakeup
|
||||
interrupt. The WdogWakeup_IRQHandler() function will be called when a wake up
|
||||
interrupt occurs. You must provide the implementation of the WdogWakeup_IRQHandler()
|
||||
function to suit your application.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
|
||||
Example:
|
||||
@code
|
||||
#include "mss_watchdog.h"
|
||||
int main( void )
|
||||
{
|
||||
MSS_WD_init( 0x10000000, MSS_WDOG_NO_WINDOW, MSS_WDOG_INTERRUPT_ON_TIMEOUT_MODE );
|
||||
MSS_WD_enable_wakeup_irq();
|
||||
for (;;)
|
||||
{
|
||||
main_task();
|
||||
cortex_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
void WdogWakeup_IRQHandler( void )
|
||||
{
|
||||
process_wakeup();
|
||||
MSS_WD_clear_wakeup_irq();
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
static __INLINE void MSS_WD_enable_wakeup_irq( void )
|
||||
{
|
||||
WATCHDOG->WDOGCONTROL |= MSS_WDOG_WAKEUP_IRQ_ENABLE_BIT_MASK;
|
||||
NVIC_EnableIRQ( WdogWakeup_IRQn );
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_disable_wakeup_irq() function disables the SmartFusion wakeup
|
||||
interrupt.
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
*/
|
||||
static __INLINE void MSS_WD_disable_wakeup_irq( void )
|
||||
{
|
||||
WATCHDOG->WDOGCONTROL &= ~MSS_WDOG_WAKEUP_IRQ_ENABLE_BIT_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_clear_timeout_irq() function clears the watchdog’s time out
|
||||
interrupt which is connected to the Cortex-M3 NMI interrupt.
|
||||
Calling MSS_WD_clear_timeout_irq() results in clearing the Cortex-M3 NMI interrupt.
|
||||
Note: The MSS_WD_clear_timeout_irq() function must be called as part of the
|
||||
timeout interrupt service routine (ISR) in order to prevent the same interrupt
|
||||
event retriggering a call to the wakeup ISR.
|
||||
|
||||
@return
|
||||
The example below demonstrates the use of the MSS_WD_clear_timeout_irq()
|
||||
function as part of the NMI interrupt service routine.
|
||||
|
||||
Example:
|
||||
@code
|
||||
void NMI_Handler( void )
|
||||
{
|
||||
process_timeout();
|
||||
MSS_WD_clear_timeout_irq();
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
static __INLINE void MSS_WD_clear_timeout_irq( void )
|
||||
{
|
||||
WATCHDOG->WDOGRIS = MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK;
|
||||
/*
|
||||
* Perform a second write to ensure that the first write completed before
|
||||
* returning from this function. This is to account for posted writes across
|
||||
* the AHB matrix. The second write ensures that the first write has
|
||||
* completed and that the interrupt line has been de-asserted by the time
|
||||
* the function returns. Omitting the second write may result in a delay
|
||||
* in the de-assertion of the interrupt line going to the Cortex-M3 and a
|
||||
* retriggering of the interrupt.
|
||||
*/
|
||||
WATCHDOG->WDOGRIS = MSS_WDOG_TIMEOUT_IRQ_CLEAR_BIT_MASK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
The MSS_WD_clear_wakeup_irq() function clears the wakeup interrupt.
|
||||
Note: The MSS_WD_clear_wakeup_irq() function must be called as part of the
|
||||
wakeup interrupt service routine (ISR) in order to prevent the same interrupt
|
||||
event retriggering a call to the wakeup ISR. This function also clears the
|
||||
interrupt in the Cortex-M3 interrupt controller through a call to
|
||||
NVIC_ClearPendingIRQ().
|
||||
|
||||
@return
|
||||
This function does not return a value.
|
||||
|
||||
Example:
|
||||
The example below demonstrates the use of the MSS_WD_clear_wakeup_irq() function
|
||||
as part of the wakeup interrupt service routine.
|
||||
@code
|
||||
void WdogWakeup_IRQHandler( void )
|
||||
{
|
||||
do_interrupt_processing();
|
||||
|
||||
MSS_WD_clear_wakeup_irq();
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
static __INLINE void MSS_WD_clear_wakeup_irq( void )
|
||||
{
|
||||
WATCHDOG->WDOGRIS = MSS_WDOG_WAKEUP_IRQ_CLEAR_BIT_MASK;
|
||||
NVIC_ClearPendingIRQ( WdogWakeup_IRQn );
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MSS_WATCHDOG_H_ */
|
179
Demo/CORTEX_A2F200_IAR_and_Keil/ParTest.c
Normal file
179
Demo/CORTEX_A2F200_IAR_and_Keil/ParTest.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
FreeRTOS V7.0.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Simple parallel port IO routines.
|
||||
*-----------------------------------------------------------*/
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Library includes. */
|
||||
#include "mss_gpio.h"
|
||||
|
||||
#define partstMAX_LEDS 8
|
||||
|
||||
static volatile unsigned long ulGPIOState = 0UL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vParTestInitialise( void )
|
||||
{
|
||||
long x;
|
||||
|
||||
/* Initialise the GPIO */
|
||||
MSS_GPIO_init();
|
||||
|
||||
/* Set up GPIO for the LEDs. */
|
||||
for( x = 0; x < partstMAX_LEDS; x++ )
|
||||
{
|
||||
MSS_GPIO_config( ( mss_gpio_id_t ) x , MSS_GPIO_OUTPUT_MODE );
|
||||
}
|
||||
|
||||
/* All LEDs start off. */
|
||||
ulGPIOState = 0xffffffffUL;
|
||||
MSS_GPIO_set_outputs( ulGPIOState );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vParTestSetLED( unsigned portBASE_TYPE uxLED, signed portBASE_TYPE xValue )
|
||||
{
|
||||
if( uxLED < partstMAX_LEDS )
|
||||
{
|
||||
/* A critical section is used as the LEDs are also accessed from an
|
||||
interrupt. */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
if( xValue == pdTRUE )
|
||||
{
|
||||
ulGPIOState &= ~( 1UL << uxLED );
|
||||
}
|
||||
else
|
||||
{
|
||||
ulGPIOState |= ( 1UL << uxLED );
|
||||
}
|
||||
|
||||
MSS_GPIO_set_outputs( ulGPIOState );
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vParTestSetLEDFromISR( unsigned portBASE_TYPE uxLED, signed portBASE_TYPE xValue )
|
||||
{
|
||||
unsigned portBASE_TYPE uxInterruptFlags;
|
||||
|
||||
uxInterruptFlags = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||
{
|
||||
if( uxLED < partstMAX_LEDS )
|
||||
{
|
||||
if( xValue == pdTRUE )
|
||||
{
|
||||
ulGPIOState &= ~( 1UL << uxLED );
|
||||
}
|
||||
else
|
||||
{
|
||||
ulGPIOState |= ( 1UL << uxLED );
|
||||
}
|
||||
|
||||
MSS_GPIO_set_outputs( ulGPIOState );
|
||||
}
|
||||
}
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxInterruptFlags );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vParTestToggleLED( unsigned portBASE_TYPE uxLED )
|
||||
{
|
||||
if( uxLED < partstMAX_LEDS )
|
||||
{
|
||||
/* A critical section is used as the LEDs are also accessed from an
|
||||
interrupt. */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
if( ( ulGPIOState & ( 1UL << uxLED ) ) != 0UL )
|
||||
{
|
||||
ulGPIOState &= ~( 1UL << uxLED );
|
||||
}
|
||||
else
|
||||
{
|
||||
ulGPIOState |= ( 1UL << uxLED );
|
||||
}
|
||||
|
||||
MSS_GPIO_set_outputs( ulGPIOState );
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
long lParTestGetLEDState( unsigned long ulLED )
|
||||
{
|
||||
long lReturn = pdFALSE;
|
||||
|
||||
if( ulLED < partstMAX_LEDS )
|
||||
{
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
if( ( ulGPIOState & ( 1UL << ulLED ) ) == 0UL )
|
||||
{
|
||||
lReturn = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
277
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-cgi.c
Normal file
277
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-cgi.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
/**
|
||||
* \addtogroup httpd
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Web server script interface
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2006, Adam Dunkels.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
|
||||
*
|
||||
* This file is part of the uIP TCP/IP stack.
|
||||
*
|
||||
* $Id: httpd-cgi.c,v 1.2 2006/06/11 21:46:37 adam Exp $
|
||||
*
|
||||
*/
|
||||
#include "net/uip.h"
|
||||
#include "net/psock.h"
|
||||
#include "apps/httpd/httpd.h"
|
||||
#include "apps/httpd/httpd-cgi.h"
|
||||
#include "apps/httpd/httpd-fs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
HTTPD_CGI_CALL( file, "file-stats", file_stats );
|
||||
HTTPD_CGI_CALL( tcp, "tcp-connections", tcp_stats );
|
||||
HTTPD_CGI_CALL( net, "net-stats", net_stats );
|
||||
HTTPD_CGI_CALL( rtos, "rtos-stats", rtos_stats );
|
||||
HTTPD_CGI_CALL( run, "run-time", run_time );
|
||||
HTTPD_CGI_CALL( io, "led-io", led_io );
|
||||
|
||||
static const struct httpd_cgi_call *calls[] = { &file, &tcp, &net, &rtos, &run, &io, NULL };
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static PT_THREAD( nullfunction ( struct httpd_state *s, char *ptr ) )
|
||||
{
|
||||
PSOCK_BEGIN( &s->sout );
|
||||
( void ) ptr;
|
||||
( void ) PT_YIELD_FLAG;
|
||||
PSOCK_END( &s->sout );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
httpd_cgifunction httpd_cgi( char *name )
|
||||
{
|
||||
const struct httpd_cgi_call **f;
|
||||
|
||||
/* Find the matching name in the table, return the function. */
|
||||
for( f = calls; *f != NULL; ++f )
|
||||
{
|
||||
if( strncmp((*f)->name, name, strlen((*f)->name)) == 0 )
|
||||
{
|
||||
return( *f )->function;
|
||||
}
|
||||
}
|
||||
|
||||
return nullfunction;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static unsigned short generate_file_stats( void *arg )
|
||||
{
|
||||
char *f = ( char * ) arg;
|
||||
return sprintf( ( char * ) uip_appdata, "%5u", httpd_fs_count(f) );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static PT_THREAD( file_stats ( struct httpd_state *s, char *ptr ) )
|
||||
{
|
||||
PSOCK_BEGIN( &s->sout );
|
||||
|
||||
( void ) PT_YIELD_FLAG;
|
||||
|
||||
PSOCK_GENERATOR_SEND( &s->sout, generate_file_stats, strchr(ptr, ' ') + 1 );
|
||||
|
||||
PSOCK_END( &s->sout );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static const char closed[] = /* "CLOSED",*/ { 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0 };
|
||||
static const char syn_rcvd[] = /* "SYN-RCVD",*/ { 0x53, 0x59, 0x4e, 0x2d, 0x52, 0x43, 0x56, 0x44, 0 };
|
||||
static const char syn_sent[] = /* "SYN-SENT",*/ { 0x53, 0x59, 0x4e, 0x2d, 0x53, 0x45, 0x4e, 0x54, 0 };
|
||||
static const char established[] = /* "ESTABLISHED",*/ { 0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0 };
|
||||
static const char fin_wait_1[] = /* "FIN-WAIT-1",*/ { 0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, 0x54, 0x2d, 0x31, 0 };
|
||||
static const char fin_wait_2[] = /* "FIN-WAIT-2",*/ { 0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, 0x54, 0x2d, 0x32, 0 };
|
||||
static const char closing[] = /* "CLOSING",*/ { 0x43, 0x4c, 0x4f, 0x53, 0x49, 0x4e, 0x47, 0 };
|
||||
static const char time_wait[] = /* "TIME-WAIT,"*/ { 0x54, 0x49, 0x4d, 0x45, 0x2d, 0x57, 0x41, 0x49, 0x54, 0 };
|
||||
static const char last_ack[] = /* "LAST-ACK"*/ { 0x4c, 0x41, 0x53, 0x54, 0x2d, 0x41, 0x43, 0x4b, 0 };
|
||||
|
||||
static const char *states[] = { closed, syn_rcvd, syn_sent, established, fin_wait_1, fin_wait_2, closing, time_wait, last_ack };
|
||||
|
||||
static unsigned short generate_tcp_stats( void *arg )
|
||||
{
|
||||
struct uip_conn *conn;
|
||||
struct httpd_state *s = ( struct httpd_state * ) arg;
|
||||
|
||||
conn = &uip_conns[s->count];
|
||||
return sprintf( ( char * ) uip_appdata,
|
||||
"<tr><td>%d</td><td>%u.%u.%u.%u:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n", htons(conn->lport),
|
||||
htons(conn->ripaddr.u16[0]) >> 8, htons(conn->ripaddr.u16[0]) & 0xff, htons(conn->ripaddr.u16[1]) >> 8,
|
||||
htons(conn->ripaddr.u16[1]) & 0xff, htons(conn->rport), states[conn->tcpstateflags & UIP_TS_MASK], conn->nrtx, conn->timer,
|
||||
(uip_outstanding(conn)) ? '*' : ' ', (uip_stopped(conn)) ? '!' : ' ' );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static PT_THREAD( tcp_stats ( struct httpd_state *s, char *ptr ) )
|
||||
{
|
||||
PSOCK_BEGIN( &s->sout );
|
||||
( void ) ptr;
|
||||
( void ) PT_YIELD_FLAG;
|
||||
for( s->count = 0; s->count < UIP_CONNS; ++s->count )
|
||||
{
|
||||
if( (uip_conns[s->count].tcpstateflags & UIP_TS_MASK) != UIP_CLOSED )
|
||||
{
|
||||
PSOCK_GENERATOR_SEND( &s->sout, generate_tcp_stats, s );
|
||||
}
|
||||
}
|
||||
|
||||
PSOCK_END( &s->sout );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static unsigned short generate_net_stats( void *arg )
|
||||
{
|
||||
struct httpd_state *s = ( struct httpd_state * ) arg;
|
||||
return sprintf( ( char * ) uip_appdata, "%5u\n", (( uip_stats_t * ) &uip_stat)[s->count] );
|
||||
}
|
||||
|
||||
static PT_THREAD( net_stats ( struct httpd_state *s, char *ptr ) )
|
||||
{
|
||||
PSOCK_BEGIN( &s->sout );
|
||||
( void ) ptr;
|
||||
( void ) PT_YIELD_FLAG;
|
||||
#if UIP_STATISTICS
|
||||
for( s->count = 0; s->count < sizeof(uip_stat) / sizeof(uip_stats_t); ++s->count )
|
||||
{
|
||||
PSOCK_GENERATOR_SEND( &s->sout, generate_net_stats, s );
|
||||
}
|
||||
|
||||
#endif /* UIP_STATISTICS */
|
||||
|
||||
PSOCK_END( &s->sout );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
extern void vTaskList( signed char *pcWriteBuffer );
|
||||
extern char *pcGetTaskStatusMessage( void );
|
||||
static char cCountBuf[128];
|
||||
long lRefreshCount = 0;
|
||||
static unsigned short generate_rtos_stats( void *arg )
|
||||
{
|
||||
( void ) arg;
|
||||
lRefreshCount++;
|
||||
sprintf( cCountBuf, "<p><br>Refresh count = %d<p><br>%s", ( int ) lRefreshCount, pcGetTaskStatusMessage() );
|
||||
vTaskList( uip_appdata );
|
||||
strcat( uip_appdata, cCountBuf );
|
||||
|
||||
return strlen( uip_appdata );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static PT_THREAD( rtos_stats ( struct httpd_state *s, char *ptr ) )
|
||||
{
|
||||
PSOCK_BEGIN( &s->sout );
|
||||
( void ) ptr;
|
||||
( void ) PT_YIELD_FLAG;
|
||||
PSOCK_GENERATOR_SEND( &s->sout, generate_rtos_stats, NULL );
|
||||
PSOCK_END( &s->sout );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
char *pcStatus;
|
||||
unsigned long ulString;
|
||||
|
||||
static unsigned short generate_io_state( void *arg )
|
||||
{
|
||||
extern long lParTestGetLEDState( unsigned long ulLED );
|
||||
( void ) arg;
|
||||
|
||||
/* Are the dynamically setable LEDs currently on or off? */
|
||||
if( lParTestGetLEDState( 8 ) )
|
||||
{
|
||||
pcStatus = "checked";
|
||||
}
|
||||
else
|
||||
{
|
||||
pcStatus = "";
|
||||
}
|
||||
|
||||
sprintf( uip_appdata, "<input type=\"checkbox\" name=\"LED0\" value=\"1\" %s>LED<p><p>", pcStatus );
|
||||
|
||||
return strlen( uip_appdata );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
extern void vTaskGetRunTimeStats( signed char *pcWriteBuffer );
|
||||
extern unsigned short usMaxJitter;
|
||||
static char cJitterBuffer[ 200 ];
|
||||
static unsigned short generate_runtime_stats( void *arg )
|
||||
{
|
||||
( void ) arg;
|
||||
lRefreshCount++;
|
||||
sprintf( cCountBuf, "<p><br>Refresh count = %d", ( int ) lRefreshCount );
|
||||
|
||||
#ifdef INCLUDE_HIGH_FREQUENCY_TIMER_TEST
|
||||
{
|
||||
sprintf( cJitterBuffer, "<p><br>Max high frequency timer jitter = %d peripheral clock periods.<p><br>", ( int ) usMaxJitter );
|
||||
vTaskGetRunTimeStats( uip_appdata );
|
||||
strcat( uip_appdata, cJitterBuffer );
|
||||
}
|
||||
#else
|
||||
{
|
||||
( void ) cJitterBuffer;
|
||||
strcpy( uip_appdata, "<p>Run time stats are only available in the debug_with_optimisation build configuration.<p>" );
|
||||
}
|
||||
#endif
|
||||
|
||||
strcat( uip_appdata, cCountBuf );
|
||||
|
||||
return strlen( uip_appdata );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static PT_THREAD( run_time ( struct httpd_state *s, char *ptr ) )
|
||||
{
|
||||
PSOCK_BEGIN( &s->sout );
|
||||
( void ) ptr;
|
||||
( void ) PT_YIELD_FLAG;
|
||||
PSOCK_GENERATOR_SEND( &s->sout, generate_runtime_stats, NULL );
|
||||
PSOCK_END( &s->sout );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static PT_THREAD( led_io ( struct httpd_state *s, char *ptr ) )
|
||||
{
|
||||
PSOCK_BEGIN( &s->sout );
|
||||
( void ) ptr;
|
||||
( void ) PT_YIELD_FLAG;
|
||||
PSOCK_GENERATOR_SEND( &s->sout, generate_io_state, NULL );
|
||||
PSOCK_END( &s->sout );
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body bgcolor="white">
|
||||
<center>
|
||||
<h1>404 - file not found</h1>
|
||||
<h3>Go <a href="/">here</a> instead.</h3>
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>FreeRTOS.org uIP WEB server demo</title>
|
||||
</head>
|
||||
<BODY onLoad="window.setTimeout("location.href='index.shtml'",100)">
|
||||
<font face="arial">
|
||||
Loading index.shtml. Click <a href="index.shtml">here</a> if not automatically redirected.
|
||||
</font>
|
||||
</font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>FreeRTOS.org uIP WEB server demo</title>
|
||||
</head>
|
||||
<BODY onLoad="window.setTimeout("location.href='index.shtml'",2000)">
|
||||
<font face="arial">
|
||||
<a href="index.shtml">Task Stats</a> <b>|</b> <a href="runtime.shtml">Run Time Stats</a> <b>|</b> <a href="stats.shtml">TCP Stats</a> <b>|</b> <a href="tcp.shtml">Connections</a> <b>|</b> <a href="http://www.freertos.org/">FreeRTOS Homepage</a> <b>|</b> <a href="io.shtml">IO</a> <b>|</b> <a href="logo.jpg">37K jpg</a>
|
||||
<br><p>
|
||||
<hr>
|
||||
<br><p>
|
||||
<h2>Task statistics</h2>
|
||||
Page will refresh every 2 seconds.<p>
|
||||
<font face="courier"><pre>Task State Priority Stack #<br>************************************************<br>
|
||||
%! rtos-stats
|
||||
</pre></font>
|
||||
</font>
|
||||
</body>
|
||||
</html>
|
||||
|
28
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-fs/io.shtml
Normal file
28
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-fs/io.shtml
Normal file
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>FreeRTOS.org uIP WEB server demo</title>
|
||||
</head>
|
||||
<BODY>
|
||||
<font face="arial">
|
||||
<a href="index.shtml">Task Stats</a> <b>|</b> <a href="runtime.shtml">Run Time Stats</a> <b>|</b> <a href="stats.shtml">TCP Stats</a> <b>|</b> <a href="tcp.shtml">Connections</a> <b>|</b> <a href="http://www.freertos.org/">FreeRTOS Homepage</a> <b>|</b> <a href="io.shtml">IO</a> <b>|</b> <a href="logo.jpg">37K jpg</a>
|
||||
<br><p>
|
||||
<hr>
|
||||
<b>LED and LCD IO</b><br>
|
||||
|
||||
<p>
|
||||
|
||||
Use the check box to turn on or off LED 4, then click "Update IO".
|
||||
|
||||
|
||||
<p>
|
||||
<form name="aForm" action="/io.shtml" method="get">
|
||||
%! led-io
|
||||
<p>
|
||||
<input type="submit" value="Update IO">
|
||||
</form>
|
||||
<br><p>
|
||||
</font>
|
||||
</body>
|
||||
</html>
|
||||
|
BIN
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-fs/logo.jpg
Normal file
BIN
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-fs/logo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>FreeRTOS.org uIP WEB server demo</title>
|
||||
</head>
|
||||
<BODY onLoad="window.setTimeout("location.href='runtime.shtml'",2000)">
|
||||
<font face="arial">
|
||||
<a href="index.shtml">Task Stats</a> <b>|</b> <a href="runtime.shtml">Run Time Stats</a> <b>|</b> <a href="stats.shtml">TCP Stats</a> <b>|</b> <a href="tcp.shtml">Connections</a> <b>|</b> <a href="http://www.freertos.org/">FreeRTOS Homepage</a> <b>|</b> <a href="io.shtml">IO</a> <b>|</b> <a href="logo.jpg">37K jpg</a>
|
||||
<br><p>
|
||||
<hr>
|
||||
<br><p>
|
||||
<h2>Run-time statistics</h2>
|
||||
Page will refresh every 2 seconds.<p>
|
||||
<font face="courier"><pre>Task Abs Time % Time<br>****************************************<br>
|
||||
%! run-time
|
||||
</pre></font>
|
||||
</font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>FreeRTOS.org uIP WEB server demo</title>
|
||||
</head>
|
||||
<BODY>
|
||||
<font face="arial">
|
||||
<a href="index.shtml">Task Stats</a> <b>|</b> <a href="runtime.shtml">Run Time Stats</a> <b>|</b> <a href="stats.shtml">TCP Stats</a> <b>|</b> <a href="tcp.shtml">Connections</a> <b>|</b> <a href="http://www.freertos.org/">FreeRTOS Homepage</a> <b>|</b> <a href="io.shtml">IO</a> <b>|</b> <a href="logo.jpg">37K jpg</a>
|
||||
<br><p>
|
||||
<hr>
|
||||
<br><p>
|
||||
<h2>Network statistics</h2>
|
||||
<table width="300" border="0">
|
||||
<tr><td align="left"><font face="courier"><pre>
|
||||
IP Packets received
|
||||
Packets sent
|
||||
Forwaded
|
||||
Dropped
|
||||
IP errors IP version/header length
|
||||
IP length, high byte
|
||||
IP length, low byte
|
||||
IP fragments
|
||||
Header checksum
|
||||
Wrong protocol
|
||||
ICMP Packets received
|
||||
Packets sent
|
||||
Packets dropped
|
||||
Type errors
|
||||
Checksum errors
|
||||
TCP Packets received
|
||||
Packets sent
|
||||
Packets dropped
|
||||
Checksum errors
|
||||
Data packets without ACKs
|
||||
Resets
|
||||
Retransmissionsa
|
||||
Syn to closed port
|
||||
UDP Packets dropped
|
||||
Packets received
|
||||
Packets sent
|
||||
Packets chkerr
|
||||
No connection avaliable
|
||||
</pre></font></td><td><font face="courier"><pre>%! net-stats
|
||||
</pre></font></td></table>
|
||||
</font>
|
||||
</body>
|
||||
</html>
|
21
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-fs/tcp.shtml
Normal file
21
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-fs/tcp.shtml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>FreeRTOS.org uIP WEB server demo</title>
|
||||
</head>
|
||||
<BODY>
|
||||
<font face="arial">
|
||||
<a href="index.shtml">Task Stats</a> <b>|</b> <a href="runtime.shtml">Run Time Stats</a> <b>|</b> <a href="stats.shtml">TCP Stats</a> <b>|</b> <a href="tcp.shtml">Connections</a> <b>|</b> <a href="http://www.freertos.org/">FreeRTOS Homepage</a> <b>|</b> <a href="io.shtml">IO</a> <b>|</b> <a href="logo.jpg">37K jpg</a>
|
||||
<br><p>
|
||||
<hr>
|
||||
<br>
|
||||
<h2>Network connections</h2>
|
||||
<p>
|
||||
<table>
|
||||
<tr><th>Local</th><th>Remote</th><th>State</th><th>Retransmissions</th><th>Timer</th><th>Flags</th></tr>
|
||||
%! tcp-connections
|
||||
</pre></font>
|
||||
</font>
|
||||
</body>
|
||||
</html>
|
||||
|
3871
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-fsdata.c
Normal file
3871
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/httpd-fsdata.c
Normal file
File diff suppressed because it is too large
Load diff
79
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/makefsdata
Normal file
79
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/makefsdata
Normal file
|
@ -0,0 +1,79 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
open(OUTPUT, "> httpd-fsdata.c");
|
||||
|
||||
chdir("httpd-fs");
|
||||
|
||||
opendir(DIR, ".");
|
||||
@files = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR);
|
||||
closedir(DIR);
|
||||
|
||||
foreach $file (@files) {
|
||||
|
||||
if(-d $file && $file !~ /^\./) {
|
||||
print "Processing directory $file\n";
|
||||
opendir(DIR, $file);
|
||||
@newfiles = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR);
|
||||
closedir(DIR);
|
||||
printf "Adding files @newfiles\n";
|
||||
@files = (@files, map { $_ = "$file/$_" } @newfiles);
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
foreach $file (@files) {
|
||||
if(-f $file) {
|
||||
|
||||
print "Adding file $file\n";
|
||||
|
||||
open(FILE, $file) || die "Could not open file $file\n";
|
||||
binmode FILE;
|
||||
|
||||
$file =~ s-^-/-;
|
||||
$fvar = $file;
|
||||
$fvar =~ s-/-_-g;
|
||||
$fvar =~ s-\.-_-g;
|
||||
# for AVR, add PROGMEM here
|
||||
print(OUTPUT "static const char data".$fvar."[] = {\n");
|
||||
print(OUTPUT "\t/* $file */\n\t");
|
||||
for($j = 0; $j < length($file); $j++) {
|
||||
printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1)));
|
||||
}
|
||||
printf(OUTPUT "0,\n");
|
||||
|
||||
|
||||
$i = 0;
|
||||
while(read(FILE, $data, 1)) {
|
||||
if($i == 0) {
|
||||
print(OUTPUT "\t");
|
||||
}
|
||||
printf(OUTPUT "%#02x, ", unpack("C", $data));
|
||||
$i++;
|
||||
if($i == 10) {
|
||||
print(OUTPUT "\n");
|
||||
$i = 0;
|
||||
}
|
||||
}
|
||||
print(OUTPUT "0};\n\n");
|
||||
close(FILE);
|
||||
push(@fvars, $fvar);
|
||||
push(@pfiles, $file);
|
||||
}
|
||||
}
|
||||
|
||||
for($i = 0; $i < @fvars; $i++) {
|
||||
$file = $pfiles[$i];
|
||||
$fvar = $fvars[$i];
|
||||
|
||||
if($i == 0) {
|
||||
$prevfile = "NULL";
|
||||
} else {
|
||||
$prevfile = "file" . $fvars[$i - 1];
|
||||
}
|
||||
print(OUTPUT "const struct httpd_fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, ");
|
||||
print(OUTPUT "data$fvar + ". (length($file) + 1) .", ");
|
||||
print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n");
|
||||
}
|
||||
|
||||
print(OUTPUT "#define HTTPD_FS_ROOT file$fvars[$i - 1]\n\n");
|
||||
print(OUTPUT "#define HTTPD_FS_NUMFILES $i\n");
|
161
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/uip-conf.h
Normal file
161
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/uip-conf.h
Normal file
|
@ -0,0 +1,161 @@
|
|||
/**
|
||||
* \addtogroup uipopt
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \name Project-specific configuration options
|
||||
* @{
|
||||
*
|
||||
* uIP has a number of configuration options that can be overridden
|
||||
* for each project. These are kept in a project-specific uip-conf.h
|
||||
* file and all configuration names have the prefix UIP_CONF.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. Neither the name of the Institute 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 INSTITUTE 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 THE INSTITUTE OR CONTRIBUTORS 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.
|
||||
*
|
||||
* This file is part of the uIP TCP/IP stack
|
||||
*
|
||||
* $Id: uip-conf.h,v 1.6 2006/06/12 08:00:31 adam Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* An example uIP configuration file
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*/
|
||||
|
||||
#ifndef __UIP_CONF_H__
|
||||
#define __UIP_CONF_H__
|
||||
|
||||
#define UIP_CONF_EXTERNAL_BUFFER
|
||||
#define UIP_CONF_PROCESS_HTTPD_FORMS 1
|
||||
|
||||
/**
|
||||
* 8 bit datatype
|
||||
*
|
||||
* This typedef defines the 8-bit type used throughout uIP.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
typedef unsigned char u8_t;
|
||||
|
||||
/**
|
||||
* 16 bit datatype
|
||||
*
|
||||
* This typedef defines the 16-bit type used throughout uIP.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
typedef unsigned short u16_t;
|
||||
|
||||
typedef unsigned long u32_t;
|
||||
|
||||
/**
|
||||
* Statistics datatype
|
||||
*
|
||||
* This typedef defines the dataype used for keeping statistics in
|
||||
* uIP.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
typedef unsigned short uip_stats_t;
|
||||
|
||||
/**
|
||||
* Maximum number of TCP connections.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_MAX_CONNECTIONS 40
|
||||
|
||||
/**
|
||||
* Maximum number of listening TCP ports.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_MAX_LISTENPORTS 40
|
||||
|
||||
/**
|
||||
* uIP buffer size.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_BUFFER_SIZE 1480
|
||||
|
||||
/**
|
||||
* CPU byte order.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
/**
|
||||
* Logging on or off
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_LOGGING 0
|
||||
|
||||
/**
|
||||
* UDP support on or off
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_UDP 0
|
||||
|
||||
/**
|
||||
* UDP checksums on or off
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_UDP_CHECKSUMS 1
|
||||
|
||||
/**
|
||||
* uIP statistics on or off
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define UIP_CONF_STATISTICS 1
|
||||
|
||||
/* Here we include the header file for the application(s) we use in
|
||||
our project. */
|
||||
/*#include "smtp.h"*/
|
||||
/*#include "hello-world.h"*/
|
||||
/*#include "telnetd.h"*/
|
||||
#include "webserver.h"
|
||||
/*#include "dhcpc.h"*/
|
||||
/*#include "resolv.h"*/
|
||||
/*#include "webclient.h"*/
|
||||
|
||||
#define CCIF
|
||||
#endif /* __UIP_CONF_H__ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
47
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/webserver.h
Normal file
47
Demo/CORTEX_A2F200_IAR_and_Keil/WebServer/webserver.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2002, Adam Dunkels.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
|
||||
*
|
||||
* This file is part of the uIP TCP/IP stack
|
||||
*
|
||||
* $Id: webserver.h,v 1.2 2006/06/11 21:46:38 adam Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __WEBSERVER_H__
|
||||
#define __WEBSERVER_H__
|
||||
|
||||
#include "apps/httpd/httpd.h"
|
||||
|
||||
typedef struct httpd_state uip_tcp_appstate_t;
|
||||
/* UIP_APPCALL: the name of the application function. This function
|
||||
must return void and take no arguments (i.e., C type "void
|
||||
appfunc(void)"). */
|
||||
#define UIP_APPCALL httpd_appcall
|
||||
|
||||
|
||||
#endif /* __WEBSERVER_H__ */
|
378
Demo/CORTEX_A2F200_IAR_and_Keil/main-blinky.c
Normal file
378
Demo/CORTEX_A2F200_IAR_and_Keil/main-blinky.c
Normal file
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
FreeRTOS V7.0.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
|
||||
Atollic AB - Atollic provides professional embedded systems development
|
||||
tools for C/C++ development, code analysis and test automation.
|
||||
See http://www.atollic.com
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* main-blinky.c is included when the "Blinky" build configuration is used.
|
||||
* main-full.c is included when the "Full" build configuration is used.
|
||||
*
|
||||
* main-blinky.c (this file) defines a very simple demo that creates two tasks,
|
||||
* one queue, and one timer. It also demonstrates how Cortex-M3 interrupts can
|
||||
* interact with FreeRTOS tasks/timers.
|
||||
*
|
||||
* This simple demo project runs on the SmartFusion A2F-EVAL-KIT evaluation
|
||||
* board, which is populated with an A2F200M3F SmartFusion mixed signal FPGA.
|
||||
* The A2F200M3F incorporates a Cortex-M3 microcontroller.
|
||||
*
|
||||
* The idle hook function:
|
||||
* The idle hook function demonstrates how to query the amount of FreeRTOS heap
|
||||
* space that is remaining (see vApplicationIdleHook() defined in this file).
|
||||
*
|
||||
* The main() Function:
|
||||
* main() creates one software timer, one queue, and two tasks. It then starts
|
||||
* the scheduler.
|
||||
*
|
||||
* The Queue Send Task:
|
||||
* The queue send task is implemented by the prvQueueSendTask() function in
|
||||
* this file. prvQueueSendTask() sits in a loop that causes it to repeatedly
|
||||
* block for 200 milliseconds, before sending the value 100 to the queue that
|
||||
* was created within main(). Once the value is sent, the task loops back
|
||||
* around to block for another 200 milliseconds.
|
||||
*
|
||||
* The Queue Receive Task:
|
||||
* The queue receive task is implemented by the prvQueueReceiveTask() function
|
||||
* in this file. prvQueueReceiveTask() sits in a loop that causes it to
|
||||
* repeatedly attempt to read data from the queue that was created within
|
||||
* main(). When data is received, the task checks the value of the data, and
|
||||
* if the value equals the expected 100, toggles the green LED. The 'block
|
||||
* time' parameter passed to the queue receive function specifies that the task
|
||||
* should be held in the Blocked state indefinitely to wait for data to be
|
||||
* available on the queue. The queue receive task will only leave the Blocked
|
||||
* state when the queue send task writes to the queue. As the queue send task
|
||||
* writes to the queue every 200 milliseconds, the queue receive task leaves
|
||||
* the Blocked state every 200 milliseconds, and therefore toggles the LED
|
||||
* every 200 milliseconds.
|
||||
*
|
||||
* The LED Software Timer and the Button Interrupt:
|
||||
* The user button SW1 is configured to generate an interrupt each time it is
|
||||
* pressed. The interrupt service routine switches an LED on, and resets the
|
||||
* LED software timer. The LED timer has a 5000 millisecond (5 second) period,
|
||||
* and uses a callback function that is defined to just turn the LED off again.
|
||||
* Therefore, pressing the user button will turn the LED on, and the LED will
|
||||
* remain on until a full five seconds pass without the button being pressed.
|
||||
*/
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "timers.h"
|
||||
|
||||
/* Microsemi drivers/libraries. */
|
||||
#include "mss_gpio.h"
|
||||
#include "mss_watchdog.h"
|
||||
|
||||
|
||||
/* Priorities at which the tasks are created. */
|
||||
#define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
|
||||
/* The rate at which data is sent to the queue, specified in milliseconds, and
|
||||
converted to ticks using the portTICK_RATE_MS constant. */
|
||||
#define mainQUEUE_SEND_FREQUENCY_MS ( 200 / portTICK_RATE_MS )
|
||||
|
||||
/* The number of items the queue can hold. This is 1 as the receive task
|
||||
will remove items as they are added, meaning the send task should always find
|
||||
the queue empty. */
|
||||
#define mainQUEUE_LENGTH ( 1 )
|
||||
|
||||
/* The LED toggle by the queue receive task. */
|
||||
#define mainTASK_CONTROLLED_LED 0x01UL
|
||||
|
||||
/* The LED turned on by the button interrupt, and turned off by the LED timer. */
|
||||
#define mainTIMER_CONTROLLED_LED 0x02UL
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Setup the NVIC, LED outputs, and button inputs.
|
||||
*/
|
||||
static void prvSetupHardware( void );
|
||||
|
||||
/*
|
||||
* The tasks as described in the comments at the top of this file.
|
||||
*/
|
||||
static void prvQueueReceiveTask( void *pvParameters );
|
||||
static void prvQueueSendTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* The LED timer callback function. This does nothing but switch off the
|
||||
* LED defined by the mainTIMER_CONTROLLED_LED constant.
|
||||
*/
|
||||
static void vLEDTimerCallback( xTimerHandle xTimer );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queue used by both tasks. */
|
||||
static xQueueHandle xQueue = NULL;
|
||||
|
||||
/* The LED software timer. This uses vLEDTimerCallback() as its callback
|
||||
function. */
|
||||
static xTimerHandle xLEDTimer = NULL;
|
||||
|
||||
/* Maintains the current LED output state. */
|
||||
static volatile unsigned long ulGPIOState = 0UL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Configure the NVIC, LED outputs and button inputs. */
|
||||
prvSetupHardware();
|
||||
|
||||
/* Create the queue. */
|
||||
xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( unsigned long ) );
|
||||
|
||||
if( xQueue != NULL )
|
||||
{
|
||||
/* Start the two tasks as described in the comments at the top of this
|
||||
file. */
|
||||
xTaskCreate( prvQueueReceiveTask, ( signed char * ) "Rx", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_RECEIVE_TASK_PRIORITY, NULL );
|
||||
xTaskCreate( prvQueueSendTask, ( signed char * ) "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );
|
||||
|
||||
/* Create the software timer that is responsible for turning off the LED
|
||||
if the button is not pushed within 5000ms, as described at the top of
|
||||
this file. */
|
||||
xLEDTimer = xTimerCreate( ( const signed char * ) "LEDTimer", /* A text name, purely to help debugging. */
|
||||
( 5000 / portTICK_RATE_MS ), /* The timer period, in this case 5000ms (5s). */
|
||||
pdFALSE, /* This is a one shot timer, so xAutoReload is set to pdFALSE. */
|
||||
( void * ) 0, /* The ID is not used, so can be set to anything. */
|
||||
vLEDTimerCallback /* The callback function that switches the LED off. */
|
||||
);
|
||||
|
||||
/* Start the tasks and timer running. */
|
||||
vTaskStartScheduler();
|
||||
}
|
||||
|
||||
/* If all is well, the scheduler will now be running, and the following line
|
||||
will never be reached. If the following line does execute, then there was
|
||||
insufficient FreeRTOS heap memory available for the idle and/or timer tasks
|
||||
to be created. See the memory management section on the FreeRTOS web site
|
||||
for more details. */
|
||||
for( ;; );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vLEDTimerCallback( xTimerHandle xTimer )
|
||||
{
|
||||
/* The timer has expired - so no button pushes have occurred in the last
|
||||
five seconds - turn the LED off. NOTE - accessing the LED port should use
|
||||
a critical section because it is accessed from multiple tasks, and the
|
||||
button interrupt - in this trivial case, for simplicity, the critical
|
||||
section is omitted. */
|
||||
ulGPIOState |= mainTIMER_CONTROLLED_LED;
|
||||
MSS_GPIO_set_outputs( ulGPIOState );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The ISR executed when the user button is pushed. */
|
||||
void GPIO8_IRQHandler( void )
|
||||
{
|
||||
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
/* The button was pushed, so ensure the LED is on before resetting the
|
||||
LED timer. The LED timer will turn the LED off if the button is not
|
||||
pushed within 5000ms. */
|
||||
ulGPIOState &= ~mainTIMER_CONTROLLED_LED;
|
||||
MSS_GPIO_set_outputs( ulGPIOState );
|
||||
|
||||
/* This interrupt safe FreeRTOS function can be called from this interrupt
|
||||
because the interrupt priority is below the
|
||||
configMAX_SYSCALL_INTERRUPT_PRIORITY setting in FreeRTOSConfig.h. */
|
||||
xTimerResetFromISR( xLEDTimer, &xHigherPriorityTaskWoken );
|
||||
|
||||
/* Clear the interrupt before leaving. */
|
||||
MSS_GPIO_clear_irq( MSS_GPIO_8 );
|
||||
|
||||
/* If calling xTimerResetFromISR() caused a task (in this case the timer
|
||||
service/daemon task) to unblock, and the unblocked task has a priority
|
||||
higher than or equal to the task that was interrupted, then
|
||||
xHigherPriorityTaskWoken will now be set to pdTRUE, and calling
|
||||
portEND_SWITCHING_ISR() will ensure the unblocked task runs next. */
|
||||
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueSendTask( void *pvParameters )
|
||||
{
|
||||
portTickType xNextWakeTime;
|
||||
const unsigned long ulValueToSend = 100UL;
|
||||
|
||||
/* Initialise xNextWakeTime - this only needs to be done once. */
|
||||
xNextWakeTime = xTaskGetTickCount();
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Place this task in the blocked state until it is time to run again.
|
||||
The block time is specified in ticks, the constant used converts ticks
|
||||
to ms. While in the Blocked state this task will not consume any CPU
|
||||
time. */
|
||||
vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS );
|
||||
|
||||
/* Send to the queue - causing the queue receive task to unblock and
|
||||
toggle an LED. 0 is used as the block time so the sending operation
|
||||
will not block - it shouldn't need to block as the queue should always
|
||||
be empty at this point in the code. */
|
||||
xQueueSend( xQueue, &ulValueToSend, 0 );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueReceiveTask( void *pvParameters )
|
||||
{
|
||||
unsigned long ulReceivedValue;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait until something arrives in the queue - this task will block
|
||||
indefinitely provided INCLUDE_vTaskSuspend is set to 1 in
|
||||
FreeRTOSConfig.h. */
|
||||
xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );
|
||||
|
||||
/* To get here something must have been received from the queue, but
|
||||
is it the expected value? If it is, toggle the green LED. */
|
||||
if( ulReceivedValue == 100UL )
|
||||
{
|
||||
/* NOTE - accessing the LED port should use a critical section
|
||||
because it is accessed from multiple tasks, and the button interrupt
|
||||
- in this trivial case, for simplicity, the critical section is
|
||||
omitted. */
|
||||
if( ( ulGPIOState & mainTASK_CONTROLLED_LED ) != 0 )
|
||||
{
|
||||
ulGPIOState &= ~mainTASK_CONTROLLED_LED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulGPIOState |= mainTASK_CONTROLLED_LED;
|
||||
}
|
||||
MSS_GPIO_set_outputs( ulGPIOState );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSetupHardware( void )
|
||||
{
|
||||
/* Disable the Watch Dog Timer */
|
||||
MSS_WD_disable( );
|
||||
|
||||
/* Initialise the GPIO */
|
||||
MSS_GPIO_init();
|
||||
|
||||
/* Set up GPIO for the LEDs. */
|
||||
MSS_GPIO_config( MSS_GPIO_0 , MSS_GPIO_OUTPUT_MODE );
|
||||
MSS_GPIO_config( MSS_GPIO_1 , MSS_GPIO_OUTPUT_MODE );
|
||||
MSS_GPIO_config( MSS_GPIO_2 , MSS_GPIO_OUTPUT_MODE );
|
||||
MSS_GPIO_config( MSS_GPIO_3 , MSS_GPIO_OUTPUT_MODE );
|
||||
MSS_GPIO_config( MSS_GPIO_4 , MSS_GPIO_OUTPUT_MODE );
|
||||
MSS_GPIO_config( MSS_GPIO_5 , MSS_GPIO_OUTPUT_MODE );
|
||||
MSS_GPIO_config( MSS_GPIO_6 , MSS_GPIO_OUTPUT_MODE );
|
||||
MSS_GPIO_config( MSS_GPIO_7 , MSS_GPIO_OUTPUT_MODE );
|
||||
|
||||
/* All LEDs start off. */
|
||||
ulGPIOState = 0xffffffffUL;
|
||||
MSS_GPIO_set_outputs( ulGPIOState );
|
||||
|
||||
/* Setup the GPIO and the NVIC for the switch used in this simple demo. */
|
||||
NVIC_SetPriority( GPIO8_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
|
||||
NVIC_EnableIRQ( GPIO8_IRQn );
|
||||
MSS_GPIO_config( MSS_GPIO_8, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_NEGATIVE );
|
||||
MSS_GPIO_enable_irq( MSS_GPIO_8 );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationMallocFailedHook( void )
|
||||
{
|
||||
/* Called if a call to pvPortMalloc() fails because there is insufficient
|
||||
free memory available in the FreeRTOS heap. pvPortMalloc() is called
|
||||
internally by FreeRTOS API functions that create tasks, queues, software
|
||||
timers, and semaphores. The size of the FreeRTOS heap is set by the
|
||||
configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
|
||||
for( ;; );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName )
|
||||
{
|
||||
( void ) pcTaskName;
|
||||
( void ) pxTask;
|
||||
|
||||
/* Run time stack overflow checking is performed if
|
||||
configconfigCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook
|
||||
function is called if a stack overflow is detected. */
|
||||
for( ;; );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationIdleHook( void )
|
||||
{
|
||||
volatile size_t xFreeStackSpace;
|
||||
|
||||
/* This function is called on each cycle of the idle task. In this case it
|
||||
does nothing useful, other than report the amout of FreeRTOS heap that
|
||||
remains unallocated. */
|
||||
xFreeStackSpace = xPortGetFreeHeapSize();
|
||||
|
||||
if( xFreeStackSpace > 100 )
|
||||
{
|
||||
/* By now, the kernel has allocated everything it is going to, so
|
||||
if there is a lot of heap remaining unallocated then
|
||||
the value of configTOTAL_HEAP_SIZE in FreeRTOSConfig.h can be
|
||||
reduced accordingly. */
|
||||
}
|
||||
}
|
618
Demo/CORTEX_A2F200_IAR_and_Keil/main-full.c
Normal file
618
Demo/CORTEX_A2F200_IAR_and_Keil/main-full.c
Normal file
|
@ -0,0 +1,618 @@
|
|||
/*
|
||||
FreeRTOS V7.0.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:
|
||||
Atollic AB - Atollic provides professional embedded systems development
|
||||
tools for C/C++ development, code analysis and test automation.
|
||||
See http://www.atollic.com
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* main-blinky.c is included when the "Blinky" build configuration is used.
|
||||
* main-full.c is included when the "Full" build configuration is used.
|
||||
*
|
||||
* main-full.c (this file) defines a comprehensive demo that creates many
|
||||
* tasks, queues, semaphores and timers. It also demonstrates how Cortex-M3
|
||||
* interrupts can interact with FreeRTOS tasks/timers, and implements a simple
|
||||
* and small interactive web server.
|
||||
*
|
||||
* This project runs on the SmartFusion A2F-EVAL-KIT evaluation board, which
|
||||
* is populated with an A2F200M3F SmartFusion mixed signal FPGA. The A2F200M3F
|
||||
* incorporates a Cortex-M3 microcontroller.
|
||||
*
|
||||
* The main() Function:
|
||||
* main() creates three demo specific software timers, one demo specific queue,
|
||||
* and two demo specific tasks. It then creates a whole host of 'standard demo'
|
||||
* tasks/queues/semaphores, before starting the scheduler. The demo specific
|
||||
* tasks and timers are described in the comments here. The standard demo
|
||||
* tasks are described on the FreeRTOS.org web site.
|
||||
*
|
||||
* The standard demo tasks provide no specific functionality. They are
|
||||
* included to both test the FreeRTOS port, and provide examples of how the
|
||||
* various FreeRTOS API functions can be used.
|
||||
*
|
||||
* The Demo Specific Queue Send Task:
|
||||
* The queue send task is implemented by the prvQueueSendTask() function in
|
||||
* this file. prvQueueSendTask() sits in a loop that causes it to repeatedly
|
||||
* block for 200 milliseconds, before sending the value 100 to the queue that
|
||||
* was created within main(). Once the value is sent, the task loops back
|
||||
* around to block for another 200 milliseconds.
|
||||
*
|
||||
* The Demo Specific Queue Receive Task:
|
||||
* The queue receive task is implemented by the prvQueueReceiveTask() function
|
||||
* in this file. prvQueueReceiveTask() sits in a loop that causes it to
|
||||
* repeatedly attempt to read data from the queue that was created within
|
||||
* main(). When data is received, the task checks the value of the data, and
|
||||
* if the value equals the expected 100, toggles the green LED. The 'block
|
||||
* time' parameter passed to the queue receive function specifies that the task
|
||||
* should be held in the Blocked state indefinitely to wait for data to be
|
||||
* available on the queue. The queue receive task will only leave the Blocked
|
||||
* state when the queue send task writes to the queue. As the queue send task
|
||||
* writes to the queue every 200 milliseconds, the queue receive task leaves
|
||||
* the Blocked state every 200 milliseconds, and therefore toggles the LED
|
||||
* every 200 milliseconds.
|
||||
*
|
||||
* The Demo Specific LED Software Timer and the Button Interrupt:
|
||||
* The user button SW1 is configured to generate an interrupt each time it is
|
||||
* pressed. The interrupt service routine switches an LED on, and resets the
|
||||
* LED software timer. The LED timer has a 5000 millisecond (5 second) period,
|
||||
* and uses a callback function that is defined to just turn the LED off again.
|
||||
* Therefore, pressing the user button will turn the LED on, and the LED will
|
||||
* remain on until a full five seconds pass without the button being pressed.
|
||||
*
|
||||
* The Demo Specific OLED Software Timer:
|
||||
* The OLED software timer is responsible for drawing a scrolling text message
|
||||
* on the OLED.
|
||||
*
|
||||
* The Demo Specific "Check" Callback Function:
|
||||
* This is called each time the 'check' timer expires. The check timer
|
||||
* callback function inspects all the standard demo tasks to see if they are
|
||||
* all executing as expected. The check timer is initially configured to
|
||||
* expire every three seconds, but will shorted this to every 500ms if an error
|
||||
* is ever discovered. The check timer callback toggles the LED defined by
|
||||
* the mainCHECK_LED definition each time it executes. Therefore, if LED
|
||||
* mainCHECK_LED is toggling every three seconds, then no error have been found.
|
||||
* If LED mainCHECK_LED is toggling every 500ms, then at least one error has
|
||||
* been found. The task in which the error was discovered is displayed at the
|
||||
* bottom of the "task stats" page that is served by the embedded web server.
|
||||
*
|
||||
* The Demo Specific Idle Hook Function:
|
||||
* The idle hook function demonstrates how to query the amount of FreeRTOS heap
|
||||
* space that is remaining (see vApplicationIdleHook() defined in this file).
|
||||
*
|
||||
* The Web Server Task:
|
||||
* The IP address used by the SmartFusion target is configured by the
|
||||
* definitions configIP_ADDR0 to configIP_ADDR3, which are located in the
|
||||
* FreeRTOSConfig.h header file. See the documentation page for this example
|
||||
* on the http://www.FreeRTOS.org web site for further connection information.
|
||||
*/
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "timers.h"
|
||||
|
||||
/* Microsemi drivers/libraries includes. */
|
||||
#include "mss_gpio.h"
|
||||
#include "mss_watchdog.h"
|
||||
#include "oled.h"
|
||||
|
||||
/* Common demo includes. */
|
||||
#include "partest.h"
|
||||
#include "flash.h"
|
||||
#include "BlockQ.h"
|
||||
#include "death.h"
|
||||
#include "blocktim.h"
|
||||
#include "semtest.h"
|
||||
#include "GenQTest.h"
|
||||
#include "QPeek.h"
|
||||
#include "recmutex.h"
|
||||
#include "TimerDemo.h"
|
||||
|
||||
/* Priorities at which the tasks are created. */
|
||||
#define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
|
||||
/* The rate at which data is sent to the queue, specified in milliseconds, and
|
||||
converted to ticks using the portTICK_RATE_MS constant. */
|
||||
#define mainQUEUE_SEND_FREQUENCY_MS ( 200 / portTICK_RATE_MS )
|
||||
|
||||
/* The number of items the queue can hold. This is 1 as the receive task
|
||||
will remove items as they are added, meaning the send task should always find
|
||||
the queue empty. */
|
||||
#define mainQUEUE_LENGTH ( 1 )
|
||||
|
||||
/* The LED toggled by the check timer callback function. */
|
||||
#define mainCHECK_LED 0x07UL
|
||||
|
||||
/* The LED turned on by the button interrupt, and turned off by the LED timer. */
|
||||
#define mainTIMER_CONTROLLED_LED 0x06UL
|
||||
|
||||
/* The LED toggle by the queue receive task. */
|
||||
#define mainTASK_CONTROLLED_LED 0x05UL
|
||||
|
||||
/* Constant used by the standard timer test functions. */
|
||||
#define mainTIMER_TEST_PERIOD ( 50 )
|
||||
|
||||
/* Priorities used by the various different tasks. */
|
||||
#define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
||||
#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define mainCREATOR_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 )
|
||||
#define mainFLASH_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define mainuIP_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY )
|
||||
|
||||
/* The WEB server uses string handling functions, which in turn use a bit more
|
||||
stack than most of the other tasks. */
|
||||
#define mainuIP_STACK_SIZE ( configMINIMAL_STACK_SIZE * 3 )
|
||||
|
||||
/* The period at which the check timer will expire, in ms, provided no errors
|
||||
have been reported by any of the standard demo tasks. */
|
||||
#define mainCHECK_TIMER_PERIOD_ms ( 3000UL )
|
||||
|
||||
/* The period at which the OLED timer will expire. Each time it expires, it's
|
||||
callback function updates the OLED text. */
|
||||
#define mainOLED_PERIOD_ms ( 75UL )
|
||||
|
||||
/* The period at which the check timer will expire, in ms, if an error has been
|
||||
reported in one of the standard demo tasks. */
|
||||
#define mainERROR_CHECK_TIMER_PERIOD_ms ( 500UL )
|
||||
|
||||
/* A zero block time. */
|
||||
#define mainDONT_BLOCK ( 0UL )
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Setup the NVIC, LED outputs, and button inputs.
|
||||
*/
|
||||
static void prvSetupHardware( void );
|
||||
|
||||
/*
|
||||
* The tasks as described in the comments at the top of this file.
|
||||
*/
|
||||
static void prvQueueReceiveTask( void *pvParameters );
|
||||
static void prvQueueSendTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* The LED timer callback function. This does nothing but switch the red LED
|
||||
* off.
|
||||
*/
|
||||
static void vLEDTimerCallback( xTimerHandle xTimer );
|
||||
|
||||
/*
|
||||
* The check timer callback function, as described at the top of this file.
|
||||
*/
|
||||
static void vCheckTimerCallback( xTimerHandle xTimer );
|
||||
|
||||
/*
|
||||
* The OLED timer callback function, as described at the top of this file.
|
||||
*/
|
||||
static void vOLEDTimerCallback( xTimerHandle xHandle );
|
||||
|
||||
/*
|
||||
* This is not a 'standard' partest function, so the prototype is not in
|
||||
* partest.h, and is instead included here.
|
||||
*/
|
||||
void vParTestSetLEDFromISR( unsigned portBASE_TYPE uxLED, signed portBASE_TYPE xValue );
|
||||
|
||||
/*
|
||||
* Contains the implementation of the WEB server.
|
||||
*/
|
||||
extern void vuIP_Task( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queue used by both application specific demo tasks defined in this file. */
|
||||
static xQueueHandle xQueue = NULL;
|
||||
|
||||
/* The LED software timer. This uses vLEDTimerCallback() as it's callback
|
||||
function. */
|
||||
static xTimerHandle xLEDTimer = NULL;
|
||||
|
||||
/* The check timer. This uses vCheckTimerCallback() as it's callback
|
||||
function. */
|
||||
static xTimerHandle xCheckTimer = NULL;
|
||||
|
||||
/* The OLED software timer. Writes a moving text string to the OLED. */
|
||||
static xTimerHandle xOLEDTimer = NULL;
|
||||
|
||||
/* The status message that is displayed at the bottom of the "task stats" web
|
||||
page, which is served by the uIP task. This will report any errors picked up
|
||||
by the check timer callback. */
|
||||
static const char *pcStatusMessage = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Configure the NVIC, LED outputs and button inputs. */
|
||||
prvSetupHardware();
|
||||
|
||||
/* Create the queue. */
|
||||
xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( unsigned long ) );
|
||||
|
||||
if( xQueue != NULL )
|
||||
{
|
||||
/* Start the two application specific demo tasks, as described in the
|
||||
comments at the top of this file. */
|
||||
xTaskCreate( prvQueueReceiveTask, ( signed char * ) "Rx", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_RECEIVE_TASK_PRIORITY, NULL );
|
||||
xTaskCreate( prvQueueSendTask, ( signed char * ) "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );
|
||||
|
||||
/* Create the software timer that is responsible for turning off the LED
|
||||
if the button is not pushed within 5000ms, as described at the top of
|
||||
this file. */
|
||||
xLEDTimer = xTimerCreate( ( const signed char * ) "LEDTimer", /* A text name, purely to help debugging. */
|
||||
( 5000 / portTICK_RATE_MS ), /* The timer period, in this case 5000ms (5s). */
|
||||
pdFALSE, /* This is a one shot timer, so xAutoReload is set to pdFALSE. */
|
||||
( void * ) 0, /* The ID is not used, so can be set to anything. */
|
||||
vLEDTimerCallback /* The callback function that switches the LED off. */
|
||||
);
|
||||
|
||||
/* Create the software timer that performs the 'check' functionality,
|
||||
as described at the top of this file. */
|
||||
xCheckTimer = xTimerCreate( ( const signed char * ) "CheckTimer", /* A text name, purely to help debugging. */
|
||||
( mainCHECK_TIMER_PERIOD_ms / portTICK_RATE_MS ),/* The timer period, in this case 3000ms (3s). */
|
||||
pdTRUE, /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */
|
||||
( void * ) 0, /* The ID is not used, so can be set to anything. */
|
||||
vCheckTimerCallback /* The callback function that inspects the status of all the other tasks. */
|
||||
);
|
||||
|
||||
/* Create the OLED timer as described at the top of this file. */
|
||||
xOLEDTimer = xTimerCreate( ( const signed char * ) "OLEDTimer", ( mainOLED_PERIOD_ms / portTICK_RATE_MS ), pdTRUE, ( void * ) 0, vOLEDTimerCallback );
|
||||
|
||||
/* Create a lot of 'standard demo' tasks. */
|
||||
vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );
|
||||
vCreateBlockTimeTasks();
|
||||
vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );
|
||||
vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY );
|
||||
vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );
|
||||
vStartQueuePeekTasks();
|
||||
vStartRecursiveMutexTasks();
|
||||
vStartTimerDemoTask( mainTIMER_TEST_PERIOD );
|
||||
|
||||
/* Create the web server task. */
|
||||
// xTaskCreate( vuIP_Task, ( signed char * ) "uIP", mainuIP_STACK_SIZE, NULL, mainuIP_TASK_PRIORITY, NULL );
|
||||
|
||||
/* Start the tasks and timer running. */
|
||||
vTaskStartScheduler();
|
||||
}
|
||||
|
||||
/* If all is well, the scheduler will now be running, and the following line
|
||||
will never be reached. If the following line does execute, then there was
|
||||
insufficient FreeRTOS heap memory available for the idle and/or timer tasks
|
||||
to be created. See the memory management section on the FreeRTOS web site
|
||||
for more details. */
|
||||
for( ;; );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCheckTimerCallback( xTimerHandle xTimer )
|
||||
{
|
||||
/* Check the standard demo tasks are running without error. Latch the
|
||||
latest reported error in the pcStatusMessage character pointer. */
|
||||
if( xAreGenericQueueTasksStillRunning() != pdTRUE )
|
||||
{
|
||||
pcStatusMessage = "Error: GenQueue";
|
||||
}
|
||||
|
||||
if( xAreQueuePeekTasksStillRunning() != pdTRUE )
|
||||
{
|
||||
pcStatusMessage = "Error: QueuePeek\r\n";
|
||||
}
|
||||
|
||||
if( xAreBlockingQueuesStillRunning() != pdTRUE )
|
||||
{
|
||||
pcStatusMessage = "Error: BlockQueue\r\n";
|
||||
}
|
||||
|
||||
if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )
|
||||
{
|
||||
pcStatusMessage = "Error: BlockTime\r\n";
|
||||
}
|
||||
|
||||
if( xAreSemaphoreTasksStillRunning() != pdTRUE )
|
||||
{
|
||||
pcStatusMessage = "Error: SemTest\r\n";
|
||||
}
|
||||
|
||||
if( xIsCreateTaskStillRunning() != pdTRUE )
|
||||
{
|
||||
pcStatusMessage = "Error: Death\r\n";
|
||||
}
|
||||
|
||||
if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )
|
||||
{
|
||||
pcStatusMessage = "Error: RecMutex\r\n";
|
||||
}
|
||||
|
||||
if( xAreTimerDemoTasksStillRunning( ( mainCHECK_TIMER_PERIOD_ms / portTICK_RATE_MS ) ) != pdTRUE )
|
||||
{
|
||||
pcStatusMessage = "Error: TimerDemo";
|
||||
}
|
||||
|
||||
/* Toggle the check LED to give an indication of the system status. If
|
||||
the LED toggles every mainCHECK_TIMER_PERIOD_ms milliseconds then
|
||||
everything is ok. A faster toggle indicates an error. */
|
||||
vParTestToggleLED( mainCHECK_LED );
|
||||
|
||||
/* Have any errors been latch in pcStatusMessage? If so, shorten the
|
||||
period of the check timer to mainERROR_CHECK_TIMER_PERIOD_ms milliseconds.
|
||||
This will result in an increase in the rate at which mainCHECK_LED
|
||||
toggles. */
|
||||
if( pcStatusMessage != NULL )
|
||||
{
|
||||
/* This call to xTimerChangePeriod() uses a zero block time. Functions
|
||||
called from inside of a timer callback function must *never* attempt
|
||||
to block. */
|
||||
xTimerChangePeriod( xCheckTimer, ( mainERROR_CHECK_TIMER_PERIOD_ms / portTICK_RATE_MS ), mainDONT_BLOCK );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vLEDTimerCallback( xTimerHandle xTimer )
|
||||
{
|
||||
/* The timer has expired - so no button pushes have occurred in the last
|
||||
five seconds - turn the LED off. */
|
||||
vParTestSetLED( mainTIMER_CONTROLLED_LED, pdFALSE );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The ISR executed when the user button is pushed. */
|
||||
void GPIO8_IRQHandler( void )
|
||||
{
|
||||
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
/* The button was pushed, so ensure the LED is on before resetting the
|
||||
LED timer. The LED timer will turn the LED off if the button is not
|
||||
pushed within 5000ms. */
|
||||
vParTestSetLEDFromISR( mainTIMER_CONTROLLED_LED, pdTRUE );
|
||||
|
||||
/* This interrupt safe FreeRTOS function can be called from this interrupt
|
||||
because the interrupt priority is below the
|
||||
configMAX_SYSCALL_INTERRUPT_PRIORITY setting in FreeRTOSConfig.h. */
|
||||
xTimerResetFromISR( xLEDTimer, &xHigherPriorityTaskWoken );
|
||||
|
||||
/* Clear the interrupt before leaving. */
|
||||
MSS_GPIO_clear_irq( MSS_GPIO_8 );
|
||||
|
||||
/* If calling xTimerResetFromISR() caused a task (in this case the timer
|
||||
service/daemon task) to unblock, and the unblocked task has a priority
|
||||
higher than or equal to the task that was interrupted, then
|
||||
xHigherPriorityTaskWoken will now be set to pdTRUE, and calling
|
||||
portEND_SWITCHING_ISR() will ensure the unblocked task runs next. */
|
||||
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueSendTask( void *pvParameters )
|
||||
{
|
||||
portTickType xNextWakeTime;
|
||||
const unsigned long ulValueToSend = 100UL;
|
||||
|
||||
/* The suicide tasks must be created last, as they need to know how many
|
||||
tasks were running prior to their creation in order to ascertain whether
|
||||
or not the correct/expected number of tasks are running at any given time.
|
||||
Therefore the standard demo 'death' tasks are not created in main(), but
|
||||
instead created here. */
|
||||
vCreateSuicidalTasks( mainCREATOR_TASK_PRIORITY );
|
||||
|
||||
/* The timer command queue will have been filled when the timer test tasks
|
||||
were created in main() (this is part of the test they perform). Therefore,
|
||||
while the check and OLED timers can be created in main(), they cannot be
|
||||
started from main(). Once the scheduler has started, the timer service
|
||||
task will drain the command queue, and now the check and OLED timers can be
|
||||
started successfully. */
|
||||
xTimerStart( xCheckTimer, portMAX_DELAY );
|
||||
xTimerStart( xOLEDTimer, portMAX_DELAY );
|
||||
|
||||
/* Initialise xNextWakeTime - this only needs to be done once. */
|
||||
xNextWakeTime = xTaskGetTickCount();
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Place this task in the blocked state until it is time to run again.
|
||||
The block time is specified in ticks, the constant used converts ticks
|
||||
to ms. While in the Blocked state this task will not consume any CPU
|
||||
time. */
|
||||
vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS );
|
||||
|
||||
/* Send to the queue - causing the queue receive task to unblock and
|
||||
toggle an LED. 0 is used as the block time so the sending operation
|
||||
will not block - it shouldn't need to block as the queue should always
|
||||
be empty at this point in the code. */
|
||||
xQueueSend( xQueue, &ulValueToSend, 0 );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueReceiveTask( void *pvParameters )
|
||||
{
|
||||
unsigned long ulReceivedValue;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait until something arrives in the queue - this task will block
|
||||
indefinitely provided INCLUDE_vTaskSuspend is set to 1 in
|
||||
FreeRTOSConfig.h. */
|
||||
xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );
|
||||
|
||||
/* To get here something must have been received from the queue, but
|
||||
is it the expected value? If it is, toggle the LED. */
|
||||
if( ulReceivedValue == 100UL )
|
||||
{
|
||||
vParTestToggleLED( mainTASK_CONTROLLED_LED );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vOLEDTimerCallback( xTimerHandle xHandle )
|
||||
{
|
||||
volatile size_t xFreeStackSpace;
|
||||
static struct oled_data xOLEDData;
|
||||
static unsigned char ucOffset1 = 0, ucOffset2 = 5;
|
||||
|
||||
/* This function is called on each cycle of the idle task. In this case it
|
||||
does nothing useful, other than report the amount of FreeRTOS heap that
|
||||
remains unallocated. */
|
||||
xFreeStackSpace = xPortGetFreeHeapSize();
|
||||
|
||||
if( xFreeStackSpace > 100 )
|
||||
{
|
||||
/* By now, the kernel has allocated everything it is going to, so
|
||||
if there is a lot of heap remaining unallocated then
|
||||
the value of configTOTAL_HEAP_SIZE in FreeRTOSConfig.h can be
|
||||
reduced accordingly. */
|
||||
}
|
||||
|
||||
xOLEDData.line1 = FIRST_LINE;
|
||||
xOLEDData.char_offset1 = ucOffset1++;
|
||||
xOLEDData.string1 = "www.FreeRTOS.org";
|
||||
|
||||
xOLEDData.line2 = SECOND_LINE;
|
||||
xOLEDData.char_offset2 = ucOffset2++;
|
||||
xOLEDData.string2 = "www.FreeRTOS.org";
|
||||
|
||||
xOLEDData.contrast_val = OLED_CONTRAST_VAL;
|
||||
xOLEDData.on_off = OLED_HORIZ_SCROLL_OFF;
|
||||
xOLEDData.column_scrool_per_step = OLED_HORIZ_SCROLL_STEP;
|
||||
xOLEDData.start_page = OLED_START_PAGE;
|
||||
xOLEDData.time_intrval_btw_scroll_step = OLED_HORIZ_SCROLL_TINVL;
|
||||
xOLEDData.end_page = OLED_END_PAGE;
|
||||
|
||||
OLED_write_data( &xOLEDData, BOTH_LINES );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSetupHardware( void )
|
||||
{
|
||||
/* Disable the Watch Dog Timer */
|
||||
MSS_WD_disable( );
|
||||
|
||||
/* Configure the GPIO for the LEDs. */
|
||||
vParTestInitialise();
|
||||
|
||||
/* Initialise the display. */
|
||||
OLED_init();
|
||||
|
||||
/* Setup the GPIO and the NVIC for the switch used in this simple demo. */
|
||||
NVIC_SetPriority( GPIO8_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
|
||||
NVIC_EnableIRQ( GPIO8_IRQn );
|
||||
MSS_GPIO_config( MSS_GPIO_8, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_NEGATIVE );
|
||||
MSS_GPIO_enable_irq( MSS_GPIO_8 );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationMallocFailedHook( void )
|
||||
{
|
||||
/* Called if a call to pvPortMalloc() fails because there is insufficient
|
||||
free memory available in the FreeRTOS heap. pvPortMalloc() is called
|
||||
internally by FreeRTOS API functions that create tasks, queues, software
|
||||
timers, and semaphores. The size of the FreeRTOS heap is set by the
|
||||
configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
|
||||
for( ;; );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName )
|
||||
{
|
||||
( void ) pcTaskName;
|
||||
( void ) pxTask;
|
||||
|
||||
/* Run time stack overflow checking is performed if
|
||||
configconfigCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook
|
||||
function is called if a stack overflow is detected. */
|
||||
taskDISABLE_INTERRUPTS();
|
||||
for( ;; );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationIdleHook( void )
|
||||
{
|
||||
volatile size_t xFreeStackSpace;
|
||||
|
||||
/* This function is called on each cycle of the idle task. In this case it
|
||||
does nothing useful, other than report the amount of FreeRTOS heap that
|
||||
remains unallocated. */
|
||||
xFreeStackSpace = xPortGetFreeHeapSize();
|
||||
|
||||
if( xFreeStackSpace > 100 )
|
||||
{
|
||||
/* By now, the kernel has allocated everything it is going to, so
|
||||
if there is a lot of heap remaining unallocated then
|
||||
the value of configTOTAL_HEAP_SIZE in FreeRTOSConfig.h can be
|
||||
reduced accordingly. */
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
char *pcGetTaskStatusMessage( void )
|
||||
{
|
||||
/* Not bothered about a critical section here although technically because
|
||||
of the task priorities the pointer could change it will be atomic if not
|
||||
near atomic and its not critical. */
|
||||
if( pcStatusMessage == NULL )
|
||||
{
|
||||
return "All tasks running without error";
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( char * ) pcStatusMessage;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
293
Demo/CORTEX_A2F200_IAR_and_Keil/printf-stdarg.c
Normal file
293
Demo/CORTEX_A2F200_IAR_and_Keil/printf-stdarg.c
Normal file
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
Copyright 2001, 2002 Georges Menie (www.menie.org)
|
||||
stdarg version contributed by Christian Ettinger
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
putchar is the only external dependency for this file,
|
||||
if you have a working putchar, leave it commented out.
|
||||
If not, uncomment the define below and
|
||||
replace outbyte(c) by your own function call.
|
||||
|
||||
*/
|
||||
|
||||
#define putchar(c) c
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static void printchar(char **str, int c)
|
||||
{
|
||||
//extern int putchar(int c);
|
||||
|
||||
if (str) {
|
||||
**str = (char)c;
|
||||
++(*str);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)putchar(c);
|
||||
}
|
||||
}
|
||||
|
||||
#define PAD_RIGHT 1
|
||||
#define PAD_ZERO 2
|
||||
|
||||
static int prints(char **out, const char *string, int width, int pad)
|
||||
{
|
||||
register int pc = 0, padchar = ' ';
|
||||
|
||||
if (width > 0) {
|
||||
register int len = 0;
|
||||
register const char *ptr;
|
||||
for (ptr = string; *ptr; ++ptr) ++len;
|
||||
if (len >= width) width = 0;
|
||||
else width -= len;
|
||||
if (pad & PAD_ZERO) padchar = '0';
|
||||
}
|
||||
if (!(pad & PAD_RIGHT)) {
|
||||
for ( ; width > 0; --width) {
|
||||
printchar (out, padchar);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
for ( ; *string ; ++string) {
|
||||
printchar (out, *string);
|
||||
++pc;
|
||||
}
|
||||
for ( ; width > 0; --width) {
|
||||
printchar (out, padchar);
|
||||
++pc;
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
/* the following should be enough for 32 bit int */
|
||||
#define PRINT_BUF_LEN 12
|
||||
|
||||
static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase)
|
||||
{
|
||||
char print_buf[PRINT_BUF_LEN];
|
||||
register char *s;
|
||||
register int t, neg = 0, pc = 0;
|
||||
register unsigned int u = (unsigned int)i;
|
||||
|
||||
if (i == 0) {
|
||||
print_buf[0] = '0';
|
||||
print_buf[1] = '\0';
|
||||
return prints (out, print_buf, width, pad);
|
||||
}
|
||||
|
||||
if (sg && b == 10 && i < 0) {
|
||||
neg = 1;
|
||||
u = (unsigned int)-i;
|
||||
}
|
||||
|
||||
s = print_buf + PRINT_BUF_LEN-1;
|
||||
*s = '\0';
|
||||
|
||||
while (u) {
|
||||
t = (unsigned int)u % b;
|
||||
if( t >= 10 )
|
||||
t += letbase - '0' - 10;
|
||||
*--s = (char)(t + '0');
|
||||
u /= b;
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
if( width && (pad & PAD_ZERO) ) {
|
||||
printchar (out, '-');
|
||||
++pc;
|
||||
--width;
|
||||
}
|
||||
else {
|
||||
*--s = '-';
|
||||
}
|
||||
}
|
||||
|
||||
return pc + prints (out, s, width, pad);
|
||||
}
|
||||
|
||||
static int print( char **out, const char *format, va_list args )
|
||||
{
|
||||
register int width, pad;
|
||||
register int pc = 0;
|
||||
char scr[2];
|
||||
|
||||
for (; *format != 0; ++format) {
|
||||
if (*format == '%') {
|
||||
++format;
|
||||
width = pad = 0;
|
||||
if (*format == '\0') break;
|
||||
if (*format == '%') goto out;
|
||||
if (*format == '-') {
|
||||
++format;
|
||||
pad = PAD_RIGHT;
|
||||
}
|
||||
while (*format == '0') {
|
||||
++format;
|
||||
pad |= PAD_ZERO;
|
||||
}
|
||||
for ( ; *format >= '0' && *format <= '9'; ++format) {
|
||||
width *= 10;
|
||||
width += *format - '0';
|
||||
}
|
||||
if( *format == 's' ) {
|
||||
register char *s = (char *)va_arg( args, int );
|
||||
pc += prints (out, s?s:"(null)", width, pad);
|
||||
continue;
|
||||
}
|
||||
if( *format == 'd' ) {
|
||||
pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a');
|
||||
continue;
|
||||
}
|
||||
if( *format == 'x' ) {
|
||||
pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a');
|
||||
continue;
|
||||
}
|
||||
if( *format == 'X' ) {
|
||||
pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A');
|
||||
continue;
|
||||
}
|
||||
if( *format == 'u' ) {
|
||||
pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a');
|
||||
continue;
|
||||
}
|
||||
if( *format == 'c' ) {
|
||||
/* char are converted to int then pushed on the stack */
|
||||
scr[0] = (char)va_arg( args, int );
|
||||
scr[1] = '\0';
|
||||
pc += prints (out, scr, width, pad);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
out:
|
||||
printchar (out, *format);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
if (out) **out = '\0';
|
||||
va_end( args );
|
||||
return pc;
|
||||
}
|
||||
|
||||
int printf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start( args, format );
|
||||
return print( 0, format, args );
|
||||
}
|
||||
|
||||
int sprintf(char *out, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start( args, format );
|
||||
return print( &out, format, args );
|
||||
}
|
||||
|
||||
|
||||
int snprintf( char *buf, unsigned int count, const char *format, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
( void ) count;
|
||||
|
||||
va_start( args, format );
|
||||
return print( &buf, format, args );
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST_PRINTF
|
||||
int main(void)
|
||||
{
|
||||
char *ptr = "Hello world!";
|
||||
char *np = 0;
|
||||
int i = 5;
|
||||
unsigned int bs = sizeof(int)*8;
|
||||
int mi;
|
||||
char buf[80];
|
||||
|
||||
mi = (1 << (bs-1)) + 1;
|
||||
printf("%s\n", ptr);
|
||||
printf("printf test\n");
|
||||
printf("%s is null pointer\n", np);
|
||||
printf("%d = 5\n", i);
|
||||
printf("%d = - max int\n", mi);
|
||||
printf("char %c = 'a'\n", 'a');
|
||||
printf("hex %x = ff\n", 0xff);
|
||||
printf("hex %02x = 00\n", 0);
|
||||
printf("signed %d = unsigned %u = hex %x\n", -3, -3, -3);
|
||||
printf("%d %s(s)%", 0, "message");
|
||||
printf("\n");
|
||||
printf("%d %s(s) with %%\n", 0, "message");
|
||||
sprintf(buf, "justif: \"%-10s\"\n", "left"); printf("%s", buf);
|
||||
sprintf(buf, "justif: \"%10s\"\n", "right"); printf("%s", buf);
|
||||
sprintf(buf, " 3: %04d zero padded\n", 3); printf("%s", buf);
|
||||
sprintf(buf, " 3: %-4d left justif.\n", 3); printf("%s", buf);
|
||||
sprintf(buf, " 3: %4d right justif.\n", 3); printf("%s", buf);
|
||||
sprintf(buf, "-3: %04d zero padded\n", -3); printf("%s", buf);
|
||||
sprintf(buf, "-3: %-4d left justif.\n", -3); printf("%s", buf);
|
||||
sprintf(buf, "-3: %4d right justif.\n", -3); printf("%s", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* if you compile this file with
|
||||
* gcc -Wall $(YOUR_C_OPTIONS) -DTEST_PRINTF -c printf.c
|
||||
* you will get a normal warning:
|
||||
* printf.c:214: warning: spurious trailing `%' in format
|
||||
* this line is testing an invalid % at the end of the format string.
|
||||
*
|
||||
* this should display (on 32bit int machine) :
|
||||
*
|
||||
* Hello world!
|
||||
* printf test
|
||||
* (null) is null pointer
|
||||
* 5 = 5
|
||||
* -2147483647 = - max int
|
||||
* char a = 'a'
|
||||
* hex ff = ff
|
||||
* hex 00 = 00
|
||||
* signed -3 = unsigned 4294967293 = hex fffffffd
|
||||
* 0 message(s)
|
||||
* 0 message(s) with %
|
||||
* justif: "left "
|
||||
* justif: " right"
|
||||
* 3: 0003 zero padded
|
||||
* 3: 3 left justif.
|
||||
* 3: 3 right justif.
|
||||
* -3: -003 zero padded
|
||||
* -3: -3 left justif.
|
||||
* -3: -3 right justif.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* To keep linker happy. */
|
||||
int write( int i, char* c, int n)
|
||||
{
|
||||
(void)i;
|
||||
(void)n;
|
||||
(void)c;
|
||||
return 0;
|
||||
}
|
||||
|
449
Demo/CORTEX_A2F200_IAR_and_Keil/uIP_Task.c
Normal file
449
Demo/CORTEX_A2F200_IAR_and_Keil/uIP_Task.c
Normal file
|
@ -0,0 +1,449 @@
|
|||
unsigned long ulRxed = 0, ulRxISR = 0, ulTxed = 0, ulTxISR = 0;
|
||||
/*
|
||||
FreeRTOS V7.0.0 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <string.h>
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "timers.h"
|
||||
|
||||
/* uip includes. */
|
||||
#include "net/uip.h"
|
||||
#include "net/uip_arp.h"
|
||||
#include "apps/httpd/httpd.h"
|
||||
#include "sys/timer.h"
|
||||
#include "net/clock-arch.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "ParTest.h"
|
||||
|
||||
/* Hardware driver includes. */
|
||||
#include "mss_ethernet_mac_regs.h"
|
||||
#include "mss_ethernet_mac.h"
|
||||
|
||||
/* The buffer used by the uIP stack to both receive and send. This points to
|
||||
one of the Ethernet buffers when its actually in use. */
|
||||
extern unsigned char *uip_buf;
|
||||
|
||||
static const unsigned char ucMACAddress[] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 };
|
||||
|
||||
#define uipARP_TIMER 0
|
||||
#define uipPERIODIC_TIMER 1
|
||||
|
||||
#define uipEVENT_QUEUE_LENGTH 10
|
||||
|
||||
#define uipETHERNET_RX_EVENT 0x01UL
|
||||
#define uipETHERNET_TX_EVENT 0x02UL
|
||||
#define uipARP_TIMER_EVENT 0x04UL
|
||||
#define uipPERIODIC_TIMER_EVENT 0x08UL
|
||||
#define uipAPPLICATION_SEND_EVENT 0x10UL
|
||||
|
||||
#define uipDONT_BLOCK 0UL
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* How long to wait before attempting to connect the MAC again. */
|
||||
#define uipINIT_WAIT ( 100 / portTICK_RATE_MS )
|
||||
|
||||
/* Shortcut to the header within the Rx buffer. */
|
||||
#define xHeader ((struct uip_eth_hdr *) &uip_buf[ 0 ])
|
||||
|
||||
/* Standard constant. */
|
||||
#define uipTOTAL_FRAME_HEADER_SIZE 54
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Setup the MAC address in the MAC itself, and in the uIP stack.
|
||||
*/
|
||||
static void prvSetMACAddress( void );
|
||||
|
||||
/*
|
||||
* Perform any uIP initialisation required to ready the stack for http
|
||||
* processing.
|
||||
*/
|
||||
static void prvInitialise_uIP( void );
|
||||
|
||||
/*
|
||||
* Handles Ethernet interrupt events.
|
||||
*/
|
||||
static void prvEMACEventListener( unsigned long ulISREvents );
|
||||
|
||||
static void prvUIPTimerCallback( xTimerHandle xTimer );
|
||||
|
||||
/*
|
||||
* Initialise the MAC hardware.
|
||||
*/
|
||||
static void prvInitEmac( void );
|
||||
|
||||
void vEMACWrite( void );
|
||||
|
||||
long lEMACWaitForLink( void );
|
||||
|
||||
/*
|
||||
* Port functions required by the uIP stack.
|
||||
*/
|
||||
void clock_init( void );
|
||||
clock_time_t clock_time( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queue used to send TCP/IP events to the uIP stack. */
|
||||
xQueueHandle xEMACEventQueue = NULL;
|
||||
|
||||
static unsigned long ulUIP_Events = 0UL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void clock_init(void)
|
||||
{
|
||||
/* This is done when the scheduler starts. */
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
clock_time_t clock_time( void )
|
||||
{
|
||||
return xTaskGetTickCount();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vuIP_Task( void *pvParameters )
|
||||
{
|
||||
portBASE_TYPE i;
|
||||
unsigned long ulNewEvent;
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Initialise the uIP stack, configuring for web server usage. */
|
||||
prvInitialise_uIP();
|
||||
|
||||
/* Initialise the MAC. */
|
||||
prvInitEmac();
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( ( ulUIP_Events & uipETHERNET_RX_EVENT ) != 0UL )
|
||||
{
|
||||
ulUIP_Events &= ~uipETHERNET_RX_EVENT;
|
||||
|
||||
/* Is there received data ready to be processed? */
|
||||
uip_len = MSS_MAC_rx_packet();
|
||||
|
||||
if( ( uip_len > 0 ) && ( uip_buf != NULL ) )
|
||||
{
|
||||
ulRxed++;
|
||||
/* Standard uIP loop taken from the uIP manual. */
|
||||
if( xHeader->type == htons( UIP_ETHTYPE_IP ) )
|
||||
{
|
||||
uip_arp_ipin();
|
||||
uip_input();
|
||||
|
||||
/* If the above function invocation resulted in data that
|
||||
should be sent out on the network, the global variable
|
||||
uip_len is set to a value > 0. */
|
||||
if( uip_len > 0 )
|
||||
{
|
||||
uip_arp_out();
|
||||
vEMACWrite();
|
||||
}
|
||||
}
|
||||
else if( xHeader->type == htons( UIP_ETHTYPE_ARP ) )
|
||||
{
|
||||
uip_arp_arpin();
|
||||
|
||||
/* If the above function invocation resulted in data that
|
||||
should be sent out on the network, the global variable
|
||||
uip_len is set to a value > 0. */
|
||||
if( uip_len > 0 )
|
||||
{
|
||||
vEMACWrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( ( ulUIP_Events & uipPERIODIC_TIMER_EVENT ) != 0UL )
|
||||
{
|
||||
ulUIP_Events &= ~uipPERIODIC_TIMER_EVENT;
|
||||
|
||||
for( i = 0; i < UIP_CONNS; i++ )
|
||||
{
|
||||
uip_periodic( i );
|
||||
|
||||
/* If the above function invocation resulted in data that
|
||||
should be sent out on the network, the global variable
|
||||
uip_len is set to a value > 0. */
|
||||
if( uip_len > 0 )
|
||||
{
|
||||
uip_arp_out();
|
||||
vEMACWrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the ARP timer function every 10 seconds. */
|
||||
if( ( ulUIP_Events & uipARP_TIMER_EVENT ) != 0 )
|
||||
{
|
||||
ulUIP_Events &= ~uipARP_TIMER_EVENT;
|
||||
uip_arp_timer();
|
||||
}
|
||||
|
||||
if( ulUIP_Events == pdFALSE )
|
||||
{
|
||||
xQueueReceive( xEMACEventQueue, &ulNewEvent, portMAX_DELAY );
|
||||
ulUIP_Events |= ulNewEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSetMACAddress( void )
|
||||
{
|
||||
struct uip_eth_addr xAddr;
|
||||
|
||||
/* Configure the MAC address in the uIP stack. */
|
||||
xAddr.addr[ 0 ] = configMAC_ADDR0;
|
||||
xAddr.addr[ 1 ] = configMAC_ADDR1;
|
||||
xAddr.addr[ 2 ] = configMAC_ADDR2;
|
||||
xAddr.addr[ 3 ] = configMAC_ADDR3;
|
||||
xAddr.addr[ 4 ] = configMAC_ADDR4;
|
||||
xAddr.addr[ 5 ] = configMAC_ADDR5;
|
||||
uip_setethaddr( xAddr );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationProcessFormInput( char *pcInputString )
|
||||
{
|
||||
char *c;
|
||||
|
||||
/* Only interested in processing form input if this is the IO page. */
|
||||
c = strstr( pcInputString, "io.shtml" );
|
||||
|
||||
if( c )
|
||||
{
|
||||
/* Is there a command in the string? */
|
||||
c = strstr( pcInputString, "?" );
|
||||
if( c )
|
||||
{
|
||||
/* Turn the LED's on or off in accordance with the check box status. */
|
||||
if( strstr( c, "LED0=1" ) != NULL )
|
||||
{
|
||||
/* Turn the LEDs on. */
|
||||
vParTestSetLED( 7, 1 );
|
||||
vParTestSetLED( 8, 1 );
|
||||
vParTestSetLED( 9, 1 );
|
||||
vParTestSetLED( 10, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Turn the LEDs off. */
|
||||
vParTestSetLED( 7, 0 );
|
||||
vParTestSetLED( 8, 0 );
|
||||
vParTestSetLED( 9, 0 );
|
||||
vParTestSetLED( 10, 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Commands to turn LEDs off are not always explicit. */
|
||||
vParTestSetLED( 7, 0 );
|
||||
vParTestSetLED( 8, 0 );
|
||||
vParTestSetLED( 9, 0 );
|
||||
vParTestSetLED( 10, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInitialise_uIP( void )
|
||||
{
|
||||
uip_ipaddr_t xIPAddr;
|
||||
xTimerHandle xARPTimer, xPeriodicTimer;
|
||||
|
||||
uip_init();
|
||||
uip_ipaddr( &xIPAddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 );
|
||||
uip_sethostaddr( &xIPAddr );
|
||||
uip_ipaddr( &xIPAddr, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 );
|
||||
uip_setnetmask( &xIPAddr );
|
||||
prvSetMACAddress();
|
||||
httpd_init();
|
||||
|
||||
/* Create the queue used to sent TCP/IP events to the uIP stack. */
|
||||
xEMACEventQueue = xQueueCreate( uipEVENT_QUEUE_LENGTH, sizeof( unsigned long ) );
|
||||
|
||||
/* Create and start the uIP timers. */
|
||||
xARPTimer = xTimerCreate( ( const signed char * const ) "ARPTimer", /* Just a name that is helpful for debugging, not used by the kernel. */
|
||||
( 500 / portTICK_RATE_MS ), /* Timer period. */
|
||||
pdTRUE, /* Autor-reload. */
|
||||
( void * ) uipARP_TIMER,
|
||||
prvUIPTimerCallback
|
||||
);
|
||||
|
||||
xPeriodicTimer = xTimerCreate( ( const signed char * const ) "PeriodicTimer",
|
||||
( 5000 / portTICK_RATE_MS ),
|
||||
pdTRUE, /* Autor-reload. */
|
||||
( void * ) uipPERIODIC_TIMER,
|
||||
prvUIPTimerCallback
|
||||
);
|
||||
|
||||
configASSERT( xARPTimer );
|
||||
configASSERT( xPeriodicTimer );
|
||||
|
||||
xTimerStart( xARPTimer, portMAX_DELAY );
|
||||
xTimerStart( xPeriodicTimer, portMAX_DELAY );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEMACEventListener( unsigned long ulISREvents )
|
||||
{
|
||||
long lHigherPriorityTaskWoken = pdFALSE;
|
||||
unsigned long ulUIPEvents = 0UL;
|
||||
|
||||
configASSERT( xEMACEventQueue );
|
||||
|
||||
if( ( ulISREvents & MSS_MAC_EVENT_PACKET_SEND ) != 0UL )
|
||||
{
|
||||
ulTxISR++;
|
||||
MSS_MAC_TxBufferCompleted();
|
||||
}
|
||||
|
||||
if( ( ulISREvents & MSS_MAC_EVENT_PACKET_RECEIVED ) != 0UL )
|
||||
{
|
||||
ulRxISR++;
|
||||
/* Wake the uIP task as new data has arrived. */
|
||||
ulUIPEvents |= uipETHERNET_RX_EVENT;
|
||||
}
|
||||
|
||||
if( ulUIPEvents != 0UL )
|
||||
{
|
||||
xQueueSendFromISR( xEMACEventQueue, &ulUIPEvents, &lHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInitEmac( void )
|
||||
{
|
||||
const unsigned char ucPHYAddress = 1;
|
||||
|
||||
MSS_MAC_init( ucPHYAddress );
|
||||
|
||||
MSS_MAC_set_callback( prvEMACEventListener );
|
||||
|
||||
/* Setup the EMAC and the NVIC for MAC interrupts. */
|
||||
NVIC_SetPriority( EthernetMAC_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
|
||||
NVIC_EnableIRQ( EthernetMAC_IRQn );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vEMACWrite( void )
|
||||
{
|
||||
const long lMaxAttempts = 10;
|
||||
long lAttempt;
|
||||
const portTickType xShortDelay = ( 10 / portTICK_RATE_MS );
|
||||
|
||||
for( lAttempt = 0; lAttempt < lMaxAttempts; lAttempt++ )
|
||||
{
|
||||
if( MSS_MAC_tx_packet( uip_len ) != 0 )
|
||||
{
|
||||
ulTxed++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
vTaskDelay( xShortDelay );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
long lEMACWaitForLink( void )
|
||||
{
|
||||
long lReturn = pdFAIL;
|
||||
unsigned long ulStatus;
|
||||
|
||||
ulStatus = MSS_MAC_link_status();
|
||||
if( ( ulStatus & ( unsigned long ) MSS_MAC_LINK_STATUS_LINK ) != 0UL )
|
||||
{
|
||||
lReturn = pdPASS;
|
||||
}
|
||||
|
||||
return lReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvUIPTimerCallback( xTimerHandle xTimer )
|
||||
{
|
||||
static const unsigned long ulARPTimerExpired = uipARP_TIMER_EVENT;
|
||||
static const unsigned long ulPeriodicTimerExpired = uipPERIODIC_TIMER_EVENT;
|
||||
|
||||
/* This is a time callback, so calls to xQueueSend() must not attempt to
|
||||
block. */
|
||||
switch( ( int ) pvTimerGetTimerID( xTimer ) )
|
||||
{
|
||||
case uipARP_TIMER : xQueueSend( xEMACEventQueue, &ulARPTimerExpired, uipDONT_BLOCK );
|
||||
break;
|
||||
|
||||
case uipPERIODIC_TIMER : xQueueSend( xEMACEventQueue, &ulPeriodicTimerExpired, uipDONT_BLOCK );
|
||||
break;
|
||||
|
||||
default : /* Should not get here. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
Loading…
Reference in a new issue