Add SmartFusion/SoftConsole demo. At the moment only the blinky configuration is included. The full configuration will be added soon.

This commit is contained in:
Richard Barry 2011-04-03 19:02:58 +00:00
parent 0e62058edb
commit f74e406997
50 changed files with 26065 additions and 0 deletions

View file

@ -0,0 +1,316 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?>
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="cdt.managedbuild.config.gnu.cross.cortexm3.exe.debug.1240723558">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.cortexm3.exe.debug.1240723558" moduleId="org.eclipse.cdt.core.settings" name="Debug">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="RTOSDemo" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.cortexm3.exe.debug.1240723558" name="Debug" parent="cdt.managedbuild.config.gnu.cross.cortexm3.exe.debug">
<folderInfo id="cdt.managedbuild.config.gnu.cross.cortexm3.exe.debug.1240723558." name="/" resourcePath="">
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.cortexm3.exe.debug.1726660630" name="Microsemi Cortex-M3 Tools" superClass="cdt.managedbuild.toolchain.gnu.cross.cortexm3.exe.debug">
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.cross.cortexm3.exe.debug.1035922613" name="Debug Platform" osList="all" superClass="cdt.managedbuild.target.gnu.platform.cross.cortexm3.exe.debug"/>
<builder buildPath="${workspace_loc:/RTOSDemo/Debug}" id="cdt.managedbuild.target.gnu.builder.cross.cortexm3.exe.debug.248091448" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.cross.cortexm3.exe.debug"/>
<tool id="cdt.managedbuild.tool.gnu.c.compiler.cross.cortexm3.exe.debug.1071303895" name="GNU C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.cross.cortexm3.exe.debug">
<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.cross.cortexm3.exe.debug.option.optimization.level.510955399" name="Optimization Level" superClass="gnu.c.compiler.cross.cortexm3.exe.debug.option.optimization.level" valueType="enumerated"/>
<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.cross.cortexm3.exe.debug.option.debugging.level.779446663" name="Debug Level" superClass="gnu.c.compiler.cross.cortexm3.exe.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
<option id="gnu.c.compiler.option.include.paths.1134958080" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/RTOSDemo/FreeRTOS_Source/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/RTOSDemo/FreeRTOS_Source/portable/GCC/ARM_CM3}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/RTOSDemo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/RTOSDemo/MicroSemi_Code/drivers/mss_gpio}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/RTOSDemo/MicroSemi_Code/drivers/mss_watchdog}&quot;"/>
</option>
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1656219383" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.cross.cortexm3.exe.debug.1468299398" name="GNU C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.cross.cortexm3.exe.debug">
<option id="gnu.cpp.compiler.cross.cortexm3.exe.debug.option.optimization.level.2285143" name="Optimization Level" superClass="gnu.cpp.compiler.cross.cortexm3.exe.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
<option id="gnu.cpp.compiler.cross.cortexm3.exe.debug.option.debugging.level.679011726" name="Debug Level" superClass="gnu.cpp.compiler.cross.cortexm3.exe.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.c.linker.cross.cortexm3.exe.debug.442931082" name="GNU C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.cross.cortexm3.exe.debug">
<option id="gnu.c.link.option.ldflags.1590630226" name="Linker flags" superClass="gnu.c.link.option.ldflags" value="-T ../MicroSemi_Code/CMSIS/startup_gcc/debug-in-actel-smartfusion-envm.ld" valueType="string"/>
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.289727023" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
</inputType>
</tool>
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.cross.cortexm3.exe.debug.1350537504" name="GNU C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.cross.cortexm3.exe.debug"/>
<tool id="cdt.managedbuild.tool.gnu.assembler.cross.cortexm3.exe.debug.1697516927" name="GNU Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.cross.cortexm3.exe.debug">
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.2018963534" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
</tool>
<tool id="com.actel.softconsole.memory-map.gen.cross.cortexm3.xml.debug.660351128" name="Memory map generator" superClass="com.actel.softconsole.memory-map.gen.cross.cortexm3.xml.debug"/>
<tool id="cdt.managedbuild.tool.gnu.objcopy.cross.cortexm3.ihex.debug.1122450256" name="GNU Intel Hex File Generator" superClass="cdt.managedbuild.tool.gnu.objcopy.cross.cortexm3.ihex.debug"/>
<tool id="cdt.managedbuild.tool.gnu.objcopy.cross.cortexm3.srec.debug.1806709351" name="GNU S-Record Generator" superClass="cdt.managedbuild.tool.gnu.objcopy.cross.cortexm3.srec.debug"/>
<tool id="cdt.managedbuild.tool.gnu.objdump.cross.cortexm3.lst.debug.1964401485" name="GNU Listing Generator" superClass="cdt.managedbuild.tool.gnu.objdump.cross.cortexm3.lst.debug"/>
</toolChain>
</folderInfo>
<sourceEntries>
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="FreeRTOS_Source"/>
<entry excluding="MicroSemi_Code/drivers/mss_uart|MicroSemi_Code/drivers/mss_spi|MicroSemi_Code/drivers/mss_pdma|MicroSemi_Code/drivers/mss_ethernet_mac|MicroSemi_Code/drivers/mss_ace|MicroSemi_Code/drivers/mac|Debug/FreeRTOS_Source/portable/GCC/ARM_CM3|Debug/FreeRTOS_Source/portable/MemMang|FreeRTOS_Source" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
<profile id="com.actel.softconsole.arm.ActelARMManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="com.actel.softconsole.core8051s.SDCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="false" filePath=""/>
<parser enabled="false"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-V -E -Wp -P -dD ${plugin_state_location}/${specs_file}" command="sdcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="com.actel.softconsole.cortexm1.ActelCortexM1ManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="com.actel.softconsole.cortexm3.ActelCortexM3ManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.cortexm3.exe.debug.1240723558;cdt.managedbuild.config.gnu.cross.cortexm3.exe.debug.1240723558.">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.actel.softconsole.cortexm3.ActelCortexM3ManagedMakePerProjectProfile"/>
<profile id="com.actel.softconsole.arm.ActelARMManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="com.actel.softconsole.core8051s.SDCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="false" filePath=""/>
<parser enabled="false"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-V -E -Wp -P -dD ${plugin_state_location}/${specs_file}" command="sdcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="com.actel.softconsole.cortexm1.ActelCortexM1ManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="com.actel.softconsole.cortexm3.ActelCortexM3ManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="RTOSDemo.cdt.managedbuild.target.gnu.cross.cortexm3.exe.1129961176" name="Executable (Managed Make)" projectType="cdt.managedbuild.target.gnu.cross.cortexm3.exe"/>
</storageModule>
</cproject>

View file

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>RTOSDemo</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<arguments>
<dictionary>
<key>?name?</key>
<value></value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.append_environment</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
<value>all</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildArguments</key>
<value></value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildCommand</key>
<value>make</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildLocation</key>
<value>${workspace_loc:/RTOSDemo/Debug}</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
<value>clean</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.contents</key>
<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
<value>all</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.stopOnError</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
<value>true</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,3 @@
#Sun Apr 03 18:36:27 BST 2011
eclipse.preferences.version=1
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false

View file

@ -0,0 +1,36 @@
REM This file should be executed from the command line prior to the first
REM build. It will be necessary to refresh the Eclipse project once the
REM .bat file has been executed (normally just press F5 to refresh).
REM Copies all the required files from their location within the standard
REM FreeRTOS directory structure to under the Eclipse project directory.
REM This permits the Eclipse project to be used in 'managed' mode and without
REM having to setup any linked resources.
REM Have the files already been copied?
IF EXIST FreeRTOS_Source Goto END
REM Create the required directory structure.
MD FreeRTOS_Source
MD FreeRTOS_Source\include
MD FreeRTOS_Source\portable\GCC
MD FreeRTOS_Source\portable\GCC\ARM_CM3
MD FreeRTOS_Source\portable\MemMang
REM Copy the core kernel files.
copy ..\..\Source\tasks.c FreeRTOS_Source
copy ..\..\Source\queue.c FreeRTOS_Source
copy ..\..\Source\list.c FreeRTOS_Source
copy ..\..\Source\timers.c FreeRTOS_Source
REM Copy the common header files
copy ..\..\Source\include\*.* FreeRTOS_Source\include
REM Copy the portable layer files
copy ..\..\Source\portable\GCC\ARM_CM3\*.* FreeRTOS_Source\portable\GCC\ARM_CM3
REM Copy the basic memory allocation files
copy ..\..\Source\portable\MemMang\heap_1.c FreeRTOS_Source\portable\MemMang
: END

View file

@ -0,0 +1,142 @@
/*
FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
***************************************************************************
* *
* If you are: *
* *
* + New to FreeRTOS, *
* + Wanting to learn FreeRTOS or multitasking in general quickly *
* + Looking for basic training, *
* + Wanting to improve your FreeRTOS skills and productivity *
* *
* then take a look at the FreeRTOS books - available as PDF or paperback *
* *
* "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
* http://www.FreeRTOS.org/Documentation *
* *
* A pdf reference manual is also available. Both are usually delivered *
* to your inbox within 20 minutes to two hours when purchased between 8am *
* and 8pm GMT (although please allow up to 24 hours in case of *
* exceptional circumstances). 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 exception 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 ) 70 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 7 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 10 )
#define configUSE_TRACE_FACILITY 0
#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 0
#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 5
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE )
/* 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 4 /* 15 priority levels */
#endif
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#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
#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,233 @@
/*******************************************************************************
* (c) Copyright 2009 SLS Corporation,All Rights Reserved.
*
* tcpip.h:header file for TCP/IP implementation.
* Version Author Comment
* 1.0.0 SLS corp. First release
*/
/***************************************************************************//**
* This header file contains the definition and datastructures for the TCP/IP
* stack implementation.
*/
#ifndef _NETTYPE_H_
#define _NETTYPE_H_
#define BUF_LEN 1500
/* IP header length in terms of 16-bit words */
#define IP_HDR_LEN 10
#define IP_HDR_CSUM_OFFSET 5
#define TCP_HDR_CSUM_OFFSET 8
#define ETH_ADDR_LEN 6
#define IP_ADDR_LEN 4
#define ETH_TYPE_LEN 2
#define ARP_HW_TYPE_LEN 2
#define ARP_PROTO_TYPE_LEN 2
#define ARP_OPCODE_LEN 2
#define ETH_TYPE_0 0x08 /* both IP and ARP have 08 as the first byte */
#define ETH_TYPE_ARP_1 0x06 /* 0806 is ARP */
#define ETH_TYPE_IP_1 0x00 /* 0800 is IP */
#define ARP_HW_TYPE_0 0x00 /* 0001 for ethernet */
#define ARP_HW_TYPE_1 0x01 /* 0001 for ethernet */
#define ARP_PROTO_TYPE_0 0x08 /* 0800 is IP */
#define ARP_PROTO_TYPE_1 0x00
#define ARP_OPCODE_0 0x00 /* same for req and reply */
#define ARP_OPCODE_REQ_1 0x01 /* 0001 is Request */
#define ARP_OPCODE_REPLY_1 0x02 /* 0002 is Reply */
extern unsigned char my_IP_address[IP_ADDR_LEN];
typedef struct ether_hdr {
unsigned char da[ETH_ADDR_LEN]; /* destination MAC address */
unsigned char sa[ETH_ADDR_LEN]; /* source MAC address */
unsigned char type_code[ETH_TYPE_LEN]; /* type code */
} ether_hdr_t;
typedef struct arp_pkt {
unsigned char hw_type[ARP_HW_TYPE_LEN]; /* Hardware Type */
unsigned char proto_type[ARP_PROTO_TYPE_LEN]; /* Protocol Type */
unsigned char hw_addr_len; /* Hardware Address Length */
unsigned char proto_addr_len; /* Protocol Address Length */
unsigned char opcode[ARP_OPCODE_LEN]; /* Opcode */
unsigned char mac_sa[ETH_ADDR_LEN]; /* sender MAC address */
unsigned char ip_sa[IP_ADDR_LEN]; /* sender IP address */
unsigned char mac_ta[ETH_ADDR_LEN]; /* target MAC address */
unsigned char ip_ta[IP_ADDR_LEN]; /* target IP address */
} arp_pkt_t;
#define ICMP_PROTO 0x01
#define TCP_PROTO 0x06
#define UDP_PROTO 0x11
#define IP_CSUM_LEN 2
#define IP_ID_LEN 2
#define IP_TLEN_LEN 2
#define IP_FRAG_OFF_LEN 2
typedef struct ip_hdr {
unsigned char ver_hlen; /* version - 4 bits; IP hdr len - 4 bits */
unsigned char tos; /* Type of service */
unsigned char tlen[IP_TLEN_LEN]; /* Size of datagram (header + data) */
unsigned char id[IP_ID_LEN]; /* together with sa, uniequly identifies pkt */
unsigned char frag_off[IP_FRAG_OFF_LEN]; /* flags - 3 bits; fragment offset - 13 bits */
unsigned char ttl; /* time to live */
unsigned char proto; /* protocol */
unsigned char csum[IP_CSUM_LEN]; /* header checksum */
unsigned char sa[IP_ADDR_LEN]; /* IP source address */
unsigned char da[IP_ADDR_LEN]; /* IP dest address */
} ip_hdr_t;
#define ICMP_TYPE_ECHO_REQUEST 8
#define ICMP_TYPE_ECHO_REPLY 0
typedef struct icmp_hdr {
unsigned char type;
unsigned char icode;
unsigned char csum[IP_CSUM_LEN];
} icmp_hdr_t;
#define TCP_PORT_LEN 2
#define TCP_SEQ_LEN 4
#define TCP_WSIZE_LEN 2
#define TCP_UPTR_LEN 2
#define TCP_CSUM_LEN 2
#define TCP_PLEN_LEN 2
typedef struct tcp_hdr {
unsigned char sp[TCP_PORT_LEN]; /* Source port */
unsigned char dp[TCP_PORT_LEN]; /* Destination port */
unsigned char seqnum[TCP_SEQ_LEN]; /* Sequence number */
unsigned char acknum[TCP_SEQ_LEN]; /* Acknowledgement number */
unsigned char data_off; /* Data Offset - 4 upper bits are valid */
unsigned char urg_ack_psh_rst_syn_fin; /* 6 lower bits are valid */
unsigned char wsize[TCP_WSIZE_LEN]; /* Window */
unsigned char csum[TCP_CSUM_LEN]; /* Chekcsum */
unsigned char uptr[TCP_UPTR_LEN]; /* Urgent pointer */
} tcp_hdr_t;
#define UDP_LEN_LEN 2
#define UDP_CSUM_LEN 2
typedef struct udp_hdr {
unsigned char sp[TCP_PORT_LEN]; /* Source port */
unsigned char dp[TCP_PORT_LEN]; /* Destination port */
unsigned char len[UDP_LEN_LEN]; /* length of packet */
unsigned char csum[UDP_CSUM_LEN]; /* checksum */
} udp_hdr_t;
#define BOOTP_OPTCODE_DHCP_SUBNET 1 /* Subnet mask */
#define BOOTP_OPTCODE_DHCP_ROUTER 3 /* Router*/
#define BOOTP_OPTCODE_DHCP_DOMAIN 6 /* Domain */
#define BOOTP_OPTCODE_DHCP_LEASE 51 /* Lease time*/
#define BOOTP_OPTCODE_DHCP_TYPE 53 /* 53, 1, DHCP_TYPE_* */
#define BOOTP_OPTCODE_DHCP_SID 54 /* 54, 4, a.b.c.d, Server ID */
#define BOOTP_OPTCODE_DHCP_RENEW 58 /* Renewal time */
#define BOOTP_OPTCODE_DHCP_REBIND 59 /* Rebinding time */
#define BOOTP_OPTCODE_END 255 /* last in options */
#define DHCP_TYPE_DISCOVER 1
#define DHCP_TYPE_OFFER 2
#define DHCP_TYPE_REQUEST 3
#define DHCP_TYPE_DECLINE 4
#define DHCP_TYPE_ACK 5
#define DHCP_TYPE_NAK 6
#define DHCP_TYPE_RELEASE 7
#define BOOTP_OP_REQUEST 1
#define BOOTP_OP_REPLY 2
#define BOOTP_HWTYPE_ETH 1
#define BOOTP_XID_LEN 4
#define BOOTP_SEC_LEN 2
#define BOOTP_CHLEN 16
#define BOOTP_SN_LEN 64
#define BOOTP_FL_LEN 128
#define BOOTP_VEN_LEN 64
#define BOOTP_CLIENT_PORT 68
#define BOOTP_SERVER_PORT 67
typedef struct bootp_pkt {
unsigned char op; /* packet op code */
unsigned char hwtype; /* hardware type */
unsigned char hlen; /* hardware address length */
unsigned char hops; /* client sets to zero */
unsigned char xid[BOOTP_XID_LEN]; /* transaction ID, random */
unsigned char secs[BOOTP_SEC_LEN]; /* seconds since boot */
unsigned char flags[2]; /* flags */
unsigned char ciaddr[IP_ADDR_LEN]; /* client IP ADDR */
unsigned char yiaddr[IP_ADDR_LEN]; /* Your IP Addr */
unsigned char siaddr[IP_ADDR_LEN]; /* Server IP ADDR */
unsigned char giaddr[IP_ADDR_LEN]; /* Gateway IP ADDR */
unsigned char chaddr[BOOTP_CHLEN]; /* Client Hardware Addr */
unsigned char sname[BOOTP_SN_LEN]; /* Server Name */
unsigned char file[BOOTP_FL_LEN]; /* File Path */
unsigned char vend[BOOTP_VEN_LEN]; /* Vendor Data */
} bootp_pkt_t;
typedef struct tcp_pseudo_hdr {
unsigned char sa[IP_ADDR_LEN];
unsigned char da[IP_ADDR_LEN];
unsigned char zero;
unsigned char proto;
unsigned char plen[TCP_PLEN_LEN];
} tcp_pseudo_hdr_t;
typedef enum tcp_state_e {
TCP_STATE_LISTEN = 0,
TCP_STATE_SYN_RECVD,
TCP_STATE_ESTABLISHED,
TCP_STATE_LAST_ACK,
TCP_STATE_MY_LAST,
TCP_STATE_CLOSED
} tcp_state_t;
typedef struct tcp_control_block {
unsigned char local_port[TCP_PORT_LEN];
unsigned char remote_port[TCP_PORT_LEN];
unsigned char remote_addr[IP_ADDR_LEN];
tcp_state_t state;
unsigned int local_seq;
unsigned int remote_seq;
unsigned char remote_mac[ETH_ADDR_LEN]; /* this really doesn't belong here */
//<CJ>:
const uint8_t * tx_block_addr;
unsigned short int tx_block_size;
unsigned short int tx_block_idx;
uint8_t * tcp_packet;
} tcp_control_block_t;
typedef enum tcp_cntrol_flags_e {
TCP_CNTRL_FIN = 0x01,
TCP_CNTRL_SYN = 0x02,
TCP_CNTRL_RST = 0x04,
TCP_CNTRL_PSH = 0x08,
TCP_CNTRL_ACK = 0x10,
TCP_CNTRL_URG = 0x20
} tcp_control_flags_t;
typedef struct arp_entry {
unsigned char mac[ETH_ADDR_LEN]; /* MAC address */
unsigned char ip[IP_ADDR_LEN]; /* IP address */
unsigned char used; /* Is this entry used? */
} arp_entry_t;
typedef arp_pkt_t *arp_pkt_xp;
typedef ether_hdr_t *eth_hdr_xp;
typedef ip_hdr_t *ip_hdr_xp;
typedef icmp_hdr_t *icmp_hdr_xp;
typedef udp_hdr_t *udp_hdr_xp;
typedef tcp_hdr_t *tcp_hdr_xp;
typedef tcp_pseudo_hdr_t *tcp_pseudo_hdr_xp;
typedef bootp_pkt_t *bootp_pkt_xp;
#endif /* _NETTYPE_H_ */

View file

@ -0,0 +1,748 @@
/*******************************************************************************
* (c) Copyright 2009 Actel Corporation,All Rights Reserved.
*
* tcpip.c:TCP/IP implementation for webserver.
*/
#include "../port_config/cpu_types.h"
#include "nettype.h"
#include "../mss_ethernet_mac/mss_ethernet_mac.h"
#include "../mss_ethernet_mac/mss_ethernet_mac_regs.h"
#include "tcpip.h"
#include <string.h>
#include <stdio.h>
#include <math.h>
#define OK 0
#define ERR 1
#define MAC_BASE_ADDRESS 0x40003000
extern char ethAddr[6];
unsigned char my_ip[IP_ADDR_LEN]={192,168,0,14};
unsigned char my_mac[ETH_ADDR_LEN]={0xAA,0xBB,0xCC,0x11,0x22,0x33};
unsigned char tcp_packet[1532];
unsigned char ip_known;
unsigned char dhcp_ip_found;
unsigned short int ip_id;
unsigned char selected_mode = 0;
unsigned char selectedwaveform = 0;
unsigned char rtc_count[5]={0,0,0,0,0};
unsigned char rtc_match_count[5]={0,5,0,0,0};
unsigned char get_count[5];
unsigned int num_pkt_tx = 0,num_pkt_rx = 0;
#define TCP_START_SEQ 0x10203040
static const unsigned char g_client_ip[IP_ADDR_LEN] = { 192, 168, 1, 10 };
unsigned char oled_string[20];
tcp_control_block_t tcb;
MAC_instance_t g_mac;
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char send_arp_reply(unsigned char *buf)
{
/* Modify the packet in place */
arp_pkt_xp arp_pkt = (arp_pkt_xp )(buf + sizeof(ether_hdr_t));
eth_hdr_xp eth_hdr = (eth_hdr_xp ) buf;
memcpy(eth_hdr->da, eth_hdr->sa, ETH_ADDR_LEN);
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN);
arp_pkt->opcode[1] = ARP_OPCODE_REPLY_1;
memcpy(arp_pkt->mac_ta, arp_pkt->mac_sa, ETH_ADDR_LEN);
memcpy(arp_pkt->ip_ta, arp_pkt->ip_sa, IP_ADDR_LEN);
memcpy(arp_pkt->mac_sa, my_mac, ETH_ADDR_LEN);
memcpy(arp_pkt->ip_sa, my_ip, IP_ADDR_LEN);
num_pkt_tx++;
MSS_MAC_tx_packet(buf,42, MSS_MAC_BLOCKING);
return OK;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
void send_gratuitous_arp(unsigned char *buf)
{
arp_pkt_xp arp_pkt = (arp_pkt_xp )(buf + sizeof(ether_hdr_t));
eth_hdr_xp eth_hdr = (eth_hdr_xp ) buf;
memset(eth_hdr->da, 0xFF, ETH_ADDR_LEN); /* broadcast */
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN);
eth_hdr->type_code[0] = ETH_TYPE_0;
eth_hdr->type_code[1] = ETH_TYPE_ARP_1;
arp_pkt->hw_type[0] = ARP_HW_TYPE_0;
arp_pkt->hw_type[1] = ARP_HW_TYPE_1;
arp_pkt->proto_type[0] = ETH_TYPE_0;
arp_pkt->proto_type[1] = ETH_TYPE_IP_1;
arp_pkt->hw_addr_len = ETH_ADDR_LEN;
arp_pkt->proto_addr_len = IP_ADDR_LEN;
arp_pkt->opcode[0] = ARP_OPCODE_0;
arp_pkt->opcode[1] = ARP_OPCODE_REQ_1;
memcpy(arp_pkt->mac_sa, my_mac, ETH_ADDR_LEN);
memcpy(arp_pkt->ip_sa, my_ip, IP_ADDR_LEN);
memset(arp_pkt->mac_ta, 0x00, ETH_ADDR_LEN);
memcpy(arp_pkt->ip_ta, my_ip, IP_ADDR_LEN);
//mac_tx_send(buf,42,0);
num_pkt_tx++;
MSS_MAC_tx_packet(buf,42, MSS_MAC_BLOCKING);
}
/***************************************************************************//**
* See tcpip.h for more information.
*
*/
unsigned short int get_checksum(unsigned char *buf, unsigned short int len, unsigned short int pos)
{
unsigned int sum; /* our accumulated sum */
unsigned short int delta; /* the next 16-bit quantity to add */
unsigned short int i;
unsigned short int ilen;
sum = (unsigned int) 0;
ilen=(len&1)?len-1:len;
for (i = 0; i < ilen; i += 2) {
if (i == pos) continue;
delta = (unsigned short int)buf[i+1] + (unsigned short int)((unsigned short int)buf[i] << 8);
sum += delta;
if (sum & (unsigned int) 0x10000) { /* if there's a carry... */
sum &= 0xffff; /* get rid of the carry bit */
sum++; /* and move it down here */
}
}
if ( len & 1) {
delta = (unsigned short int)((unsigned short int)buf[i] << 8);
sum += delta;
if (sum & (unsigned int) 0x10000) { /* if there's a carry... */
sum &= 0xffff; /* get rid of the carry bit */
sum++; /* and move it down here */
}
}
sum = ~sum;
return sum;
} //end calc_checksum
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char fix_checksum(unsigned char *buf, unsigned short int len, unsigned short int pos)
{
unsigned short int sum = get_checksum(buf,len,pos);
buf[pos] = (unsigned char)(sum >> 8);
buf[pos+1] = (unsigned char)sum;
return OK;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char check_checksum(unsigned char *buf, unsigned short int len, unsigned short int pos, char type)
{
unsigned short int sum = get_checksum(buf,len,pos);
if ((buf[pos] != (unsigned char)(sum >> 8)) ||
(buf[pos+1] != (unsigned char) sum)) {
type = 0; /* get around compiler warning */
return ERR;
} else {
return OK;
}
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char send_icmp_echo_reply(unsigned char *buf)
{
eth_hdr_xp eth_hdr = (eth_hdr_xp ) buf;
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (buf + sizeof (ether_hdr_t));
icmp_hdr_xp icmp_hdr = (icmp_hdr_xp )
(buf + sizeof (ether_hdr_t) + sizeof(ip_hdr_t));
unsigned short int elen = ((unsigned short int)ip_hdr->tlen[0] << 8) + (unsigned short int)ip_hdr->tlen[1] - sizeof(ip_hdr_t);
memcpy(eth_hdr->da, eth_hdr->sa, ETH_ADDR_LEN);
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN);
memcpy(ip_hdr->da, ip_hdr->sa, IP_ADDR_LEN);
memcpy(ip_hdr->sa, my_ip, IP_ADDR_LEN);
ip_hdr->ttl--;
fix_checksum((unsigned char *)ip_hdr, (unsigned short int) 20, (unsigned short int) 10);
icmp_hdr->type = ICMP_TYPE_ECHO_REPLY;
if (elen & 1) {
((unsigned char *)icmp_hdr)[elen] = 0;
}
fix_checksum((unsigned char *)icmp_hdr, (unsigned short int) elen, (unsigned short int) 2);
num_pkt_tx++;
MSS_MAC_tx_packet(buf,elen + sizeof(ether_hdr_t) + sizeof(ip_hdr_t), MSS_MAC_BLOCKING);
return OK;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
void dtoa_reverse(unsigned short int n, unsigned char *buf)
{
buf--;
if (n == 0) {
*buf = '0';
return;
}
while (n > 0) {
*buf-- = (n % 10) + '0';
n = n / 10;
}
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
void send_bootp_packet (unsigned char *buf)
{
/* output packet */
eth_hdr_xp eth_hdr = (eth_hdr_xp ) tcp_packet;
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t));
udp_hdr_xp udp_hdr = (udp_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t) + sizeof(ip_hdr_t));
bootp_pkt_xp bootp_pkt = (bootp_pkt_xp )((unsigned char *)udp_hdr + sizeof(udp_hdr_t));
unsigned char *opts = bootp_pkt->vend;
/* input packet */
// eth_hdr_xp ieth_hdr = (eth_hdr_xp ) buf;
// ip_hdr_xp iip_hdr = (ip_hdr_xp ) (buf + sizeof(ether_hdr_t));
udp_hdr_xp iudp_hdr = (udp_hdr_xp ) (buf + sizeof(ether_hdr_t) + sizeof(ip_hdr_t));
bootp_pkt_xp ibootp_pkt = (bootp_pkt_xp )((unsigned char *)iudp_hdr + sizeof(udp_hdr_t));
unsigned short int plen;
/* Set up Bootp */
memset(bootp_pkt, 0, sizeof(bootp_pkt_t));
bootp_pkt->op = BOOTP_OP_REQUEST;
bootp_pkt->hwtype = BOOTP_HWTYPE_ETH;
bootp_pkt->hlen = ETH_ADDR_LEN;
bootp_pkt->secs[1] = 0x64;
memcpy(bootp_pkt->chaddr, my_mac, ETH_ADDR_LEN);
bootp_pkt->flags[0] = 0x80; /* ask for a broadcast */
if (buf) {
if (memcmp(my_mac, ibootp_pkt->chaddr, ETH_ADDR_LEN)) /* not for me ignore */
return;
memcpy(my_ip, ibootp_pkt->yiaddr, IP_ADDR_LEN);
ip_known = 1;
dhcp_ip_found = 1;
memcpy(bootp_pkt->ciaddr, ibootp_pkt->yiaddr, IP_ADDR_LEN);
memcpy(bootp_pkt->xid, ibootp_pkt->xid, BOOTP_XID_LEN);
} else {
bootp_pkt->xid[0] = 0x90;
}
*opts++ = 99; /* magic number */
*opts++ = 130;
*opts++ = 83;
*opts++ = 99;
*opts++ = BOOTP_OPTCODE_DHCP_TYPE;
*opts++ = 1;
if (buf) {
*opts++ = DHCP_TYPE_REQUEST;
*opts++ = BOOTP_OPTCODE_DHCP_SID;
*opts++ = 4;
*opts++ = ibootp_pkt->siaddr[0];
*opts++ = ibootp_pkt->siaddr[1];
*opts++ = ibootp_pkt->siaddr[2];
*opts++ = ibootp_pkt->siaddr[3];
} else {
*opts++ = DHCP_TYPE_DISCOVER;
}
*opts++ = BOOTP_OPTCODE_END;
/* Set up Udp */
memset(udp_hdr, 0, sizeof(udp_hdr_t));
udp_hdr->sp[1] = BOOTP_CLIENT_PORT;
udp_hdr->dp[1] = BOOTP_SERVER_PORT;
plen = sizeof(udp_hdr_t) + sizeof(bootp_pkt_t);
udp_hdr->len[0] = plen >> 8;
udp_hdr->len[1] = (unsigned char) plen;
/* leave csum 0 */
/* Set up IP */
memset(ip_hdr, 0, sizeof(ip_hdr_t));
ip_hdr->ver_hlen = 0x45; /* IPv4 with 20 byte header */
plen += sizeof(ip_hdr_t);
ip_hdr->tlen[0] = plen >> 8;
ip_hdr->tlen[1] = (unsigned char) plen;
ip_hdr->id[0] = ip_id >> 8;
ip_hdr->id[1] = (unsigned char) ip_id;
ip_id++;
ip_hdr->ttl = 32; /* max 32 hops */
ip_hdr->proto = UDP_PROTO;
memset(ip_hdr->da, 0xFF, IP_ADDR_LEN);
fix_checksum((unsigned char *)ip_hdr, sizeof(ip_hdr_t), 10);
/* Set up Ethernet */
eth_hdr->type_code[0] = ETH_TYPE_0;
eth_hdr->type_code[1] = ETH_TYPE_IP_1;
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN);
memset(eth_hdr->da, 0xFF, ETH_ADDR_LEN); /* broadcast */
num_pkt_tx++;
MSS_MAC_tx_packet(tcp_packet,plen + sizeof(ether_hdr_t), MSS_MAC_BLOCKING);
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
void send_dhcp_server_packet (unsigned char *buf)
{
unsigned char * tcp_packet = tcp_packet;
/* output packet */
eth_hdr_xp eth_hdr = (eth_hdr_xp ) tcp_packet;
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t));
udp_hdr_xp udp_hdr = (udp_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t) + sizeof(ip_hdr_t));
bootp_pkt_xp bootp_pkt = (bootp_pkt_xp )((unsigned char *)udp_hdr + sizeof(udp_hdr_t));
unsigned char *opts = bootp_pkt->vend;
/* input packet */
eth_hdr_xp ieth_hdr = (eth_hdr_xp ) buf;
// ip_hdr_xp iip_hdr = (ip_hdr_xp ) (buf + sizeof(ether_hdr_t));
udp_hdr_xp iudp_hdr = (udp_hdr_xp ) (buf + sizeof(ether_hdr_t) + sizeof(ip_hdr_t));
bootp_pkt_xp ibootp_pkt = (bootp_pkt_xp )((unsigned char *)iudp_hdr + sizeof(udp_hdr_t));
unsigned char *iopts = ibootp_pkt->vend;
unsigned short int plen;
/* Set up Bootp */
memset(bootp_pkt, 0, sizeof(bootp_pkt_t));
bootp_pkt->op = BOOTP_OP_REPLY;
bootp_pkt->hwtype = BOOTP_HWTYPE_ETH;
bootp_pkt->hlen = ETH_ADDR_LEN;
bootp_pkt->secs[1] = 0x64;
memcpy(bootp_pkt->chaddr, ieth_hdr->sa, ETH_ADDR_LEN);
bootp_pkt->flags[0] = 0x00;
if (buf) {
memcpy(bootp_pkt->ciaddr, ibootp_pkt->yiaddr, IP_ADDR_LEN);
memcpy(bootp_pkt->yiaddr, g_client_ip, IP_ADDR_LEN);
memcpy(bootp_pkt->xid, ibootp_pkt->xid, BOOTP_XID_LEN);
} else {
bootp_pkt->xid[0] = 0x90;
}
*opts++ = 99; /* magic number */
*opts++ = 130;
*opts++ = 83;
*opts++ = 99;
*opts++ = BOOTP_OPTCODE_DHCP_TYPE;
*opts++ = 1;
if (iopts[6] == DHCP_TYPE_DISCOVER)
{
*opts++ = DHCP_TYPE_OFFER;
}
else
{
*opts++ = DHCP_TYPE_ACK;
}
/* Server ID */
*opts++ = BOOTP_OPTCODE_DHCP_SID;
*opts++ = 4;
*opts++ = my_ip[0];
*opts++ = my_ip[1];
*opts++ = my_ip[2];
*opts++ = my_ip[3];
/* Lease time (1 our) */
*opts++ = BOOTP_OPTCODE_DHCP_LEASE;
*opts++ = 4;
*opts++ = 0x00;
*opts++ = 0x00;
*opts++ = 0x0E;
*opts++ = 0x10;
/* Renewal time */
*opts++ = BOOTP_OPTCODE_DHCP_RENEW;
*opts++ = 4;
*opts++ = 0x00;
*opts++ = 0x00;
*opts++ = 0x07;
*opts++ = 0x08;
/* Rebinding time */
*opts++ = BOOTP_OPTCODE_DHCP_REBIND;
*opts++ = 4;
*opts++ = 0x00;
*opts++ = 0x00;
*opts++ = 0x0C;
*opts++ = 0x4E;
/* Subnet mask */
*opts++ = BOOTP_OPTCODE_DHCP_SUBNET;
*opts++ = 4;
*opts++ = 0xFF;
*opts++ = 0xFF;
*opts++ = 0xFF;
*opts++ = 0x00;
/* Router */
*opts++ = BOOTP_OPTCODE_DHCP_ROUTER;
*opts++ = 4;
*opts++ = my_ip[0];
*opts++ = my_ip[1];
*opts++ = my_ip[2];
*opts++ = my_ip[3];
/* Domain */
*opts++ = BOOTP_OPTCODE_DHCP_DOMAIN;
*opts++ = 4;
*opts++ = my_ip[0];
*opts++ = my_ip[1];
*opts++ = my_ip[2];
*opts++ = my_ip[3];
*opts++ = BOOTP_OPTCODE_END;
/* Set up Udp */
memset(udp_hdr, 0, sizeof(udp_hdr_t));
udp_hdr->sp[1] = BOOTP_SERVER_PORT;
udp_hdr->dp[1] = BOOTP_CLIENT_PORT;
plen = sizeof(udp_hdr_t) + sizeof(bootp_pkt_t);
udp_hdr->len[0] = plen >> 8;
udp_hdr->len[1] = (unsigned char) plen;
/* leave csum 0 */
/* Set up IP */
memset(ip_hdr, 0, sizeof(ip_hdr_t));
ip_hdr->ver_hlen = 0x45; /* IPv4 with 20 byte header */
plen += sizeof(ip_hdr_t);
ip_hdr->tlen[0] = plen >> 8;
ip_hdr->tlen[1] = (unsigned char) plen;
ip_hdr->id[0] = ip_id >> 8;
ip_hdr->id[1] = (unsigned char) ip_id;
ip_id++;
ip_hdr->ttl = 255;
ip_hdr->proto = UDP_PROTO;
memcpy(ip_hdr->sa, my_ip, IP_ADDR_LEN);
memset(ip_hdr->da, 0xFF, IP_ADDR_LEN);
fix_checksum((unsigned char *)ip_hdr, sizeof(ip_hdr_t), 10);
/* Set up Ethernet */
eth_hdr->type_code[0] = ETH_TYPE_0;
eth_hdr->type_code[1] = ETH_TYPE_IP_1;
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN);
memset(eth_hdr->da, 0xFF, ETH_ADDR_LEN); /* broadcast */
num_pkt_tx++;
MSS_MAC_tx_packet(tcp_packet,plen + sizeof(ether_hdr_t), MSS_MAC_BLOCKING);
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char process_udp_packet (unsigned char *buf)
{
udp_hdr_xp udp_hdr = (udp_hdr_xp ) (buf + sizeof(ether_hdr_t) + sizeof(ip_hdr_t));
if (udp_hdr->dp[1] != BOOTP_CLIENT_PORT) {
send_dhcp_server_packet( buf );
return OK;
}
if (ip_known) {
return ERR;
}
/* some more error checking here? */
send_bootp_packet(buf);
return OK;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
void send_tcp_packet (unsigned char control_bits,unsigned short int buflen)
{
eth_hdr_xp eth_hdr = (eth_hdr_xp ) tcp_packet;
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t));
tcp_hdr_xp tcp_hdr = (tcp_hdr_xp )
(tcp_packet + sizeof(ether_hdr_t) + sizeof(ip_hdr_t));
tcp_pseudo_hdr_xp tcp_pseudo_hdr = (tcp_pseudo_hdr_xp )
(((unsigned char *)tcp_hdr) - sizeof(tcp_pseudo_hdr_t));
unsigned char *tcp_data = tcp_packet + sizeof(ether_hdr_t) + sizeof(ip_hdr_t) + sizeof (tcp_hdr_t);
unsigned char *seqp = (unsigned char *)(&tcb.local_seq);
unsigned short int plen;
memset(tcp_hdr, 0, sizeof(tcp_hdr_t));
memcpy(tcp_hdr->sp, tcb.local_port, TCP_PORT_LEN);
memcpy(tcp_hdr->dp, tcb.remote_port, TCP_PORT_LEN);
tcp_hdr->seqnum[0] = seqp[3];
tcp_hdr->seqnum[1] = seqp[2];
tcp_hdr->seqnum[2] = seqp[1];
tcp_hdr->seqnum[3] = seqp[0];
tcb.local_seq++;
if (buflen) {
tcb.local_seq += buflen - 1;
}
if (control_bits & TCP_CNTRL_ACK) {
seqp = (unsigned char *)(&tcb.remote_seq);
tcp_hdr->acknum[3] = seqp[0];
tcp_hdr->acknum[2] = seqp[1];
tcp_hdr->acknum[1] = seqp[2];
tcp_hdr->acknum[0] = seqp[3];
}
tcp_hdr->data_off = 0x50; /* always 5 32 bit words for us */
tcp_hdr->urg_ack_psh_rst_syn_fin = control_bits;
tcp_hdr->wsize[0] = 0x08; /* this is 0x0800, which is 2K */
if (buflen & 1) {
tcp_data[buflen] = 0;
}
/* memset(tcp_pseudo_hdr, 0, sizeof(tcp_pseudo_hdr_t)); */
memcpy(tcp_pseudo_hdr->sa, my_ip, IP_ADDR_LEN);
memcpy(tcp_pseudo_hdr->da, tcb.remote_addr, IP_ADDR_LEN);
tcp_pseudo_hdr->zero = 0;
tcp_pseudo_hdr->proto = TCP_PROTO;
plen = buflen + sizeof(tcp_hdr_t);
tcp_pseudo_hdr->plen[0] = plen >> 8;
tcp_pseudo_hdr->plen[1] = (unsigned char)plen;
fix_checksum((unsigned char *)tcp_pseudo_hdr,
(unsigned short int)(plen + sizeof(tcp_pseudo_hdr_t)), (unsigned short int)28);
memset(ip_hdr, 0, sizeof(ip_hdr_t));
ip_hdr->ver_hlen = 0x45; /* IPv4 with 20 byte header */
plen += sizeof(ip_hdr_t); /* add the size of the IP Header */
ip_hdr->tlen[0] = plen >> 8;
ip_hdr->tlen[1] = (unsigned char) plen;
ip_hdr->id[0] = ip_id >> 8;
ip_hdr->id[1] = (unsigned char) ip_id;
ip_id++;
ip_hdr->ttl = 32; /* max 32 hops */
ip_hdr->proto = TCP_PROTO;
memcpy(ip_hdr->sa, my_ip, IP_ADDR_LEN);
memcpy(ip_hdr->da, tcb.remote_addr, IP_ADDR_LEN);
fix_checksum((unsigned char *)ip_hdr, sizeof(ip_hdr_t), 10);
/* Fix the Ethernet Header */
eth_hdr->type_code[0] = ETH_TYPE_0;
eth_hdr->type_code[1] = ETH_TYPE_IP_1;
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN);
memcpy(eth_hdr->da, tcb.remote_mac, ETH_ADDR_LEN); /* should be table lookup */
num_pkt_tx++;
MSS_MAC_tx_packet(tcp_packet,plen + sizeof(ether_hdr_t), MSS_MAC_BLOCKING);
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char tcp_init(void)
{
memset(&tcb,0,sizeof(tcp_control_block_t));
tcb.state = TCP_STATE_LISTEN;
ip_id = 0;
ip_known = 0;
return OK;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char hex_digits_to_byte(unsigned char u, unsigned char l)
{
if (u > '9')
u = u - 'A' + 10;
else
u = u - '0';
if (l > '9')
l = l - 'A' + 10;
else
l = l - '0';
return (u << 4) + l;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char process_icmp_packet(unsigned char *buf)
{
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (buf + sizeof (ether_hdr_t));
icmp_hdr_xp icmp_hdr = (icmp_hdr_xp )
(buf + sizeof (ether_hdr_t) + sizeof(ip_hdr_t));
unsigned short int elen = ((unsigned short int)ip_hdr->tlen[0] << 8) + (unsigned short int)ip_hdr->tlen[1] - sizeof(ip_hdr_t);
if (check_checksum((unsigned char *)icmp_hdr, (unsigned short int) elen, (unsigned short int) 2, 'M') != OK)
return ERR;
if (icmp_hdr->type != ICMP_TYPE_ECHO_REQUEST) {
return ERR;
}
return send_icmp_echo_reply(buf);
}
/* See tcpip.h for more information.
*/
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char process_tcp_packet(unsigned char *buf)
{
eth_hdr_xp eth_hdr = (eth_hdr_xp )buf;
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (buf + sizeof (ether_hdr_t));
tcp_hdr_xp tcp_hdr = (tcp_hdr_xp )
(buf + sizeof (ether_hdr_t) + sizeof(ip_hdr_t));
unsigned short int elen = ((unsigned short int)ip_hdr->tlen[0] << 8) + (unsigned short int)ip_hdr->tlen[1] - sizeof(ip_hdr_t);
unsigned char state;
if ( !memcmp(tcb.remote_addr, ip_hdr->sa, IP_ADDR_LEN) && /* same source IP */
!memcmp(tcb.remote_port, tcp_hdr->sp, TCP_PORT_LEN) && /* same source port */
!memcmp(tcb.local_port, tcp_hdr->dp, TCP_PORT_LEN)) { /* same dest port */
state = tcb.state;
} else { /* copy it over, a new IP wants in */
memcpy(tcb.remote_addr, ip_hdr->sa, IP_ADDR_LEN);
memcpy(tcb.remote_port, tcp_hdr->sp, TCP_PORT_LEN);
memcpy(tcb.local_port, tcp_hdr->dp, TCP_PORT_LEN);
memcpy(tcb.remote_mac, eth_hdr->sa, ETH_ADDR_LEN);
state = TCP_STATE_LISTEN;
}
switch (state) {
case TCP_STATE_LISTEN:
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_SYN) {
/* recd SYN : new connection; send SYN+ACK */
tcb.local_seq = TCP_START_SEQ;
tcb.remote_seq = 0;
tcb.remote_seq = (tcb.remote_seq | tcp_hdr->seqnum[0]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[1]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[2]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[3]);
tcb.remote_seq++;
send_tcp_packet( TCP_CNTRL_SYN | TCP_CNTRL_ACK, 0);
tcb.state = TCP_STATE_SYN_RECVD;
}
break;
case TCP_STATE_SYN_RECVD:
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_ACK) {
/* recd ack; send nothing */
tcb.state = TCP_STATE_ESTABLISHED;
}
else {
tcb.state = TCP_STATE_LISTEN;
}
break;
case TCP_STATE_ESTABLISHED:
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_FIN) {
/* recd fin; send ack */
/* skip CLOSE_WAIT state; send fin along with ack */
tcb.remote_seq = 0;
tcb.remote_seq = (tcb.remote_seq | tcp_hdr->seqnum[0]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[1]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[2]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[3]);
tcb.remote_seq++;
send_tcp_packet(TCP_CNTRL_ACK | TCP_CNTRL_FIN, 0);
tcb.state = TCP_STATE_LAST_ACK;
/* Default scroll message on OLED */
}
else if (tcp_hdr->dp[0] != 0 || \
tcp_hdr->dp[1] != 80) { /* HTTP Port */
break;
}
else if (elen > sizeof(tcp_hdr_t)) { /* dont respond to empty packets*/
tcb.remote_seq = 0;
tcb.remote_seq = (tcb.remote_seq | tcp_hdr->seqnum[0]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[1]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[2]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[3]);
tcb.remote_seq += (unsigned long) (elen - sizeof(tcp_hdr_t));
//send_http_response(((unsigned char *)(tcp_hdr)) + sizeof (tcp_hdr_t));
tcb.state = TCP_STATE_MY_LAST;
}
break;
case TCP_STATE_MY_LAST:
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_FIN) {
/* sent fin, got fin, ack the fin */
tcb.remote_seq = 0;
tcb.remote_seq = (tcb.remote_seq | tcp_hdr->seqnum[0]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[1]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[2]);
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[3]);
tcb.remote_seq++;
send_tcp_packet(TCP_CNTRL_ACK, 0);
tcb.state = TCP_STATE_CLOSED;
}
break;
case TCP_STATE_LAST_ACK:
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_ACK) {
/* recd ack; send nothing */
tcb.state = TCP_STATE_CLOSED;
}
/* no break here... go on to CLOSED directly */
case TCP_STATE_CLOSED:
memset (&tcb, 0, sizeof (tcp_control_block_t));
break;
default:
break;
}
return 0;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char process_ip_packet(unsigned char *buf)
{
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (buf + sizeof (ether_hdr_t));
/* Is the incoming pkt for me?
(either explicity addressed to me or a broadcast address) */
if (memcmp(my_ip, ip_hdr->da, IP_ADDR_LEN)) /* not my IP */ {
if (ip_known) {
return ERR;
}
if (ip_hdr->da[0] != 0xFF || ip_hdr->da[1] != 0xFF ||
ip_hdr->da[2] != 0xFF || ip_hdr->da[3] != 0xFF) {
return ERR;
}
}
if (check_checksum((unsigned char *)ip_hdr, (unsigned short int) 20, (unsigned short int) 10, 'I') != OK)
return ERR;
switch (ip_hdr->proto)
{
case TCP_PROTO:
return process_tcp_packet(buf);
case ICMP_PROTO:
return process_icmp_packet(buf);
case UDP_PROTO:
return process_udp_packet(buf);
default: {
return ERR;
}
}
return ERR;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char process_arp_packet(unsigned char *buf)
{
arp_pkt_xp arp_pkt = (arp_pkt_xp )(buf + sizeof(ether_hdr_t));
if (arp_pkt->opcode[1] != ARP_OPCODE_REQ_1) {
if (arp_pkt->opcode[1] == ARP_OPCODE_REPLY_1)
{
if (!memcmp(my_ip, arp_pkt->ip_sa, IP_ADDR_LEN))
{
//printf("IP conflict with MAC");
//printf("%02x:%02x:%02x:%02x:%02x:%02x",arp_pkt->mac_sa[0],arp_pkt->mac_sa[1],arp_pkt->mac_sa[2],arp_pkt->mac_sa[3],arp_pkt->mac_sa[4],arp_pkt->mac_sa[5]);
}
}
return ERR;
}
if (memcmp(my_ip, arp_pkt->ip_ta, IP_ADDR_LEN)) {
return ERR;
}
return send_arp_reply(buf);
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char process_packet( unsigned char * buf )
{
eth_hdr_xp eth_hdr;
unsigned char typ;
eth_hdr = (eth_hdr_xp ) buf;
typ = eth_hdr->type_code[0];
if (typ != ETH_TYPE_0)
{
return ERR;
}
typ = eth_hdr->type_code[1];
if (typ == ETH_TYPE_ARP_1)
{
return process_arp_packet(buf);
}
else if (typ == ETH_TYPE_IP_1) {
return process_ip_packet(buf);
}
else
{
return ERR;
}
return ERR;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
unsigned char *xstrcpy(unsigned char *d, const unsigned char *s)
{
unsigned char c;
while ((c = *s++))
(*d++ = c) ;
return d;
}
/***************************************************************************//**
* See tcpip.h for more information.
*/
// updated html page with fusion board link on page:

View file

@ -0,0 +1,234 @@
/*******************************************************************************
* (c) Copyright 2009 SLS Corporation,All Rights Reserved.
*
* tcpip.h:header file of TCP/IP implementation.
*
* Version Author Comment
* 1.0.0 SLS corp. First release,16 Jan 2009
*/
#ifndef TCPIP_H_
#define TCPIP_H_
#define FLASH_CONTEXT_INDICATOR 0x20000000
#define FLASH_SELFWAKEUP_INDICATOR 0x20000001
#define FLASH_CONTEXT_LOCATION 0x20000002
/***************************************************************************//**
* Replies to ARP requests.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
*
*/
unsigned char send_arp_reply(unsigned char *buf);
/***************************************************************************//**
* Sends gratuitous arp brodcast message to the LAN.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
*
*/
void send_gratuitous_arp(unsigned char *buf);
/***************************************************************************//**
* Calculates the checksum for Ethernet data in the header.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
* @param len Number of bytes.
* @param pos position for the check sum.
*
* @return value of the checksum
*/
unsigned short int get_checksum(unsigned char *buf, unsigned short int len, unsigned short int pos);
/***************************************************************************//**
* Calls internally to get_checksum and fixes the value of the checksum to
* position.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
* @param len Number of bytes.
* @param pos position for the check sum.
*
* @return OK
*/
unsigned char fix_checksum(unsigned char *buf, unsigned short int len, unsigned short int pos);
/***************************************************************************//**
* Checks the calculated checksum for the errors.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
* @param len Number of bytes.
* @param pos position for the check sum.
*
* @return OK If there is no error
* ERR If there is error in the data
*/
unsigned char check_checksum(unsigned char *buf, unsigned short int len, unsigned short int pos, char type);
/***************************************************************************//**
* Sends the reply to ICMP request like PING.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
*/
unsigned char send_icmp_echo_reply(unsigned char *buf);
/***************************************************************************//**
* Converts the input integer to the ascii char and fills in the buffer.
*
* @param buf To filled in by the ascii value.
* @param n integer number
*/
void dtoa_reverse(unsigned short int n, unsigned char *buf);
/***************************************************************************//**
* Sends DHCP request to the server available in LAN.
*
* @param buf Pointer to the recieved data in case of DHCP reply.Zero for request.
*/
void send_bootp_packet (unsigned char *buf);
/***************************************************************************//**
* Processes the UDP datagram.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
*/
unsigned char process_udp_packet (unsigned char *buf);
/***************************************************************************//**
* Sends TCP packet to the network.
*
* @param buf Pointer to the transmitt buffer to Ethernet MAC.
*/
void send_tcp_packet (unsigned char control_bits,unsigned short int buflen);
/***************************************************************************//**
* Initialize TCP for the software TCP/IP stack.
*
* @return OK
*/
unsigned char tcp_init(void);
/***************************************************************************//**
* Converts two hex decimal ascii digits into a sigle integer digit.
*
* @param u ascii hex digit
* l ascii hex digit
* @returm converted integer byte
*
*/
unsigned char hex_digits_to_byte(unsigned char u, unsigned char l);
/***************************************************************************//**
* Processes ICMP packets
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
*
* @return ERR if there is an error in the data
* or calls further necessary functions.
*/
unsigned char process_icmp_packet(unsigned char *buf);
/***************************************************************************//**
* Sends logo of ACTEL on the network over HTTP protocol.
* @return OK
*/
unsigned char http_send_logo ();
/***************************************************************************//**
* Sends appropriate answer to the different HTTP requests.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
* @return OK
*/
unsigned char send_http_response(unsigned char *buf);
/***************************************************************************//**
* Process incoming TCP requests and handles the TCP state machine.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
* @return OK
*/
unsigned char process_tcp_packet(unsigned char *buf);
/***************************************************************************//**
* Process incoming IP datagrams and handles the TCP state machine.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
* @return OK
*/
unsigned char process_ip_packet(unsigned char *buf);
/***************************************************************************//**
* Processes the ARP packets.
* @param buf Pointer to the recieved buffer from Ethernet MAC.
* @return OK
*/
unsigned char process_arp_packet(unsigned char *buf);
/***************************************************************************//**
* Processes incoming packets and identifies its type.
*
* @param buf Pointer to the recieved buffer from Ethernet MAC.
* @return call the function for further process
* ERR if any error
*/
unsigned char process_packet( unsigned char * buf );
/***************************************************************************//**
* copies source string to destination address.
*
* @param d Pointer to the destination
* @param s Pointer to the source
* @return The last location after copy
*
*/
unsigned char *xstrcpy(unsigned char *d, const unsigned char *s);
/***************************************************************************//**
* Sends the home page of the demonstration webserver.
*
*/
void http_send_packet();
/***************************************************************************//**
* Sends the packet for waveform mode.
*
*/
void http_send_packet_waveform();
/***************************************************************************//**
* Sends the packet for multimeter mode.
*
*/
void http_send_packet_multimeter();
/***************************************************************************//**
* Sends the packet for DAC mode.
*
*/
void http_send_packet_DAC();
/***************************************************************************//**
* Sends the packet for sleeping stopwatch.
*
*/
void http_send_packet_SLEEPING_STOPWATCH();
/***************************************************************************//**
* Sends the packet for text terminal.
*
*/
void http_send_packet_textterminal();
/***************************************************************************//**
* Sends the packet for VIT auxiliary mode.
*
*/
void http_send_packet_VIT();
/***************************************************************************//**
* Sends the packet for Real Time Data Display.
*
*/
void http_send_packet_RTDD();
/***************************************************************************//**
* Sends the packet for Stock Ticker.
*
*/
void http_send_packet_Stockticker();
/***************************************************************************//**
* Sends the packet for Gadgets mode.
*
*/
void http_send_packet_weatherblog();
/***************************************************************************//**
* Sends the packet for Selfwakeup.
*
*/
void http_send_packet_SELFWAKEUP();
/***************************************************************************//**
* Same as above mentioned functions but following functions are applicable
* to Internet Explorer.
*
*/
void http_send_packet_IE();
void http_send_packet_SELFWAKEUP_IE();
void http_send_packet_VIT_IE();
void http_send_packet_waveform_IE();
void http_send_packet_SLEEPING_STOPWATCH_IE();
void http_send_packet_DAC_IE();
void http_send_packet_multimeter_IE();
void http_send_packet_RTDD_IE();
#endif /*TCPIP_H_*/

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,595 @@
/***************************************************************************//**
* @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 to the Ethernet Controller.
* This function writes pacLen bytes of the packet contained in pacData into the
* transmit FIFO of the controller and then activates the transmitter for this
* packet. If space is available in FIFO, the function will return once lBufLen
* bytes of the packet have been placed into the FIFO and the transmitter has been
* started. The function will not wait for the transmission to complete. If space
* is not available in FIFO, the function will keep trying till time_out expires,
* if MSS_MAC_BLOCKING value is given as time_out, function will wait for the
* transmission to complete.
*
* @param pacData the pointer to the packet data to be transmitted.
* @param pacLen number of bytes in the packet to be transmitted.
* @param time_out Time out value for transmision.
* If value is #MSS_MAC_BLOCKING, there will be no time out.
* If value is #MSS_MAC_NONBLOCKING, function will return immediately
* on buffer full case.
* Otherwise value must be greater than 0 and smaller than
* 0x01000000.
* @return Returns 0 if time out occurs otherwise returns size
* of the packet.
* @see MAC_rx_packet()
*/
int32_t
MSS_MAC_tx_packet
(
const uint8_t *pacData,
uint16_t pacLen,
uint32_t time_out
);
/***************************************************************************//**
* 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.
* This function reads a packet from the receive FIFO of the controller and
* places it into pacData. If time_out parameter is zero the function will return
* immediately (after the copy operation if data is available. Otherwise the function
* will keep trying to read till time_out expires or data is read, if MSS_MAC_BLOCKING
* value is given as time_out, function will wait for the reception to complete.
*
* @param pacData The pointer to the buffer where received packet data will
* be copied. Memory for the buffer should be allocated prior
* to calling this function.
* @param pacLen Size of the buffer, which the received data will be copied in,
* given in number of bytes.
* @param time_out Time out value in milli seconds for receiving.
* if value is #MSS_MAC_BLOCKING, there will be no time out.
* if value is #MSS_MAC_NONBLOCKING, function will return immediately
* if there is no packet waiting.
* Otherwise value must be greater than 0 and smaller than
* 0x01000000.
* @return Size of packet if packet fits in pacData.
* 0 if there is no received packet.
* @see MAC_rx_pckt_size()
* @see MAC_tx_packet()
*/
int32_t
MSS_MAC_rx_packet
(
uint8_t *pacData,
uint16_t pacLen,
uint32_t time_out
);
/***************************************************************************//**
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
);
#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 0xC0u,0xB1u,0x3Cu,0x88u,0x88u,0x88u
#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,387 @@
/***************************************************************************//**
* 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"
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 )
{
int32_t a;
uint16_t reg;
int32_t exit = 1;
reg = MDIO_read( PHYREG_MIIMCR );
MDIO_write( PHYREG_MIIMCR,
(uint16_t)( MIIMCR_ENABLE_AUTONEGOTIATION |
MIIMCR_RESTART_AUTONEGOTIATION |
reg) );
for(a=0; (a<1000) && (exit); a++) {
reg = MDIO_read( PHYREG_MIIMSR );
if( (reg & MIIMSR_ANC) != 0 ) {
exit = 0;
}
}
}
/***************************************************************************//**
* 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,367 @@
/*
FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
***************************************************************************
* *
* If you are: *
* *
* + New to FreeRTOS, *
* + Wanting to learn FreeRTOS or multitasking in general quickly *
* + Looking for basic training, *
* + Wanting to improve your FreeRTOS skills and productivity *
* *
* then take a look at the FreeRTOS books - available as PDF or paperback *
* *
* "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
* http://www.FreeRTOS.org/Documentation *
* *
* A pdf reference manual is also available. Both are usually delivered *
* to your inbox within 20 minutes to two hours when purchased between 8am *
* and 8pm GMT (although please allow up to 24 hours in case of *
* exceptional circumstances). 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 exception 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.
*/
/*
This simple demo project runs on the STM32 Discovery board, which is
populated with an STM32F100RB Cortex-M3 microcontroller. The discovery board
makes an ideal low cost evaluation platform, but the 8K of RAM provided on the
STM32F100RB does not allow the simple application to demonstrate all of all the
FreeRTOS kernel features. Therefore, this simple demo only actively
demonstrates task, queue, timer and interrupt functionality. In addition, the
demo is configured to include malloc failure, idle and stack overflow hook
functions.
The idle hook function:
The idle hook function queries the amount of FreeRTOS heap space that is
remaining (see vApplicationIdleHook() defined in this file). The demo
application is configured use 7K or the available 8K of RAM as the FreeRTOS heap.
Memory is only allocated from this heap during initialisation, and this demo
only actually uses 1.6K bytes of the configured 7K available - leaving 5.4K
bytes of heap space unallocated.
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 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 green LED every 200 milliseconds.
The LED Software Timer and the Button Interrupt:
The user button B1 is configured to generate an interrupt each time it is
pressed. The interrupt service routine switches the red 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 red LED off.
Therefore, pressing the user button will turn the red 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 )
#define mainTASK_CONTROLLED_LED 0x01UL
#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 the red LED
* off.
*/
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;
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_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. */
}
}