Create directory structure to hold the (not yet created) Keil and IAR demo projects for the SmartFusion.

This commit is contained in:
Richard Barry 2011-04-20 15:09:58 +00:00
parent 779e2bf80f
commit 139708e063
65 changed files with 32939 additions and 0 deletions

View 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 */

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

View file

@ -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_ */

View file

@ -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) }
}

View file

@ -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) }
}

View file

@ -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) }
}

View file

@ -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 stdoutso 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 */
}

View file

@ -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) }
}

View file

@ -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) }
}

View file

@ -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;
}

View file

@ -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

View 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

View 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 its 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 its 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 slaves 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 slaves 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_*/

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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_ */

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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 *********************************/

View 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*/

View file

@ -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

View file

@ -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_ */

View file

@ -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

View file

@ -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 channels 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 peripherals
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 channels 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
peripherals 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 channels 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 peripherals 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 peripherals 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 peripherals 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_ */

View file

@ -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

View file

@ -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

View file

@ -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_ */

View file

@ -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 watchdogs 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 watchdogs 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_ */

View 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;
}
/*-----------------------------------------------------------*/

View 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 );
}
/** @} */

View file

@ -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>

View file

@ -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(&quot;location.href='index.shtml'&quot;,100)">
<font face="arial">
Loading index.shtml. Click <a href="index.shtml">here</a> if not automatically redirected.
</font>
</font>
</body>
</html>

View file

@ -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(&quot;location.href='index.shtml'&quot;,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>

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -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(&quot;location.href='runtime.shtml'&quot;,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>

View file

@ -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>

View 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>

File diff suppressed because it is too large Load diff

View 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");

View 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__ */
/** @} */
/** @} */

View 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__ */

View 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. */
}
}

View 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;
}
}
/*-----------------------------------------------------------*/

View 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;
}

View 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;
}
}
/*-----------------------------------------------------------*/