1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-12 10:59:54 +03:00

Review line ending handling (#4820)

* New line end handling rules

* Normalize all the line endings
This commit is contained in:
3djc 2017-04-19 10:54:43 +02:00 committed by Bertrand Songis
parent 189b65b724
commit fa951acf40
397 changed files with 252824 additions and 252713 deletions

111
.gitattributes vendored
View file

@ -1 +1,112 @@
# Handle line endings automatically for files detected as text
# and leave all files detected as binary untouched.
* text=auto
#
# The above will handle all files NOT found below
#
# These files are text and should be normalized (Convert crlf => lf)
# Source files
*.c text
*.cc text
*.cxx text
*.cpp text
*.c++ text
*.hpp text
*.h text
*.h++ text
*.hh text
*.lua text
*.pxd text
*.py text
*.py3 text
*.pyw text
*.pyx text
*.pl text
*.pm text
*.sln text eol=crlf
*.csproj text eol=crlf
*.vbproj text eol=crlf
*.vcxproj text eol=crlf
*.vcproj text eol=crlf
*.dbproj text eol=crlf
*.fsproj text eol=crlf
*.lsproj text eol=crlf
*.wixproj text eol=crlf
*.modelproj text eol=crlf
*.sqlproj text eol=crlf
*.wmaproj text eol=crlf
*.xproj text eol=crlf
*.props text eol=crlf
*.filters text eol=crlf
*.vcxitems text eol=crlf
*.sh eol=lf
# Compiled Object files
*.slo binary
*.lo binary
*.o binary
*.obj binary
# Precompiled Headers
*.gch binary
*.pch binary
# Compiled Dynamic libraries
*.so binary
*.dylib binary
*.dll binary
# Compiled Static libraries
*.lai binary
*.la binary
*.a binary
*.lib binary
# Executables
*.exe binary
*.out binary
*.app binary
# Binary files
*.db binary
*.p binary
*.pkl binary
*.pyc binary
*.pyd binary
*.pyo binary
# Documents
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
*.md text
*.adoc text
*.textile text
*.mustache text
*.csv text
*.tab text
*.tsv text
*.sql text
# Graphics
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.tif binary
*.tiff binary
*.ico binary
# SVG treated as an asset (binary) by default. If you want to treat it as text,
# comment-out the following line and uncomment the line after.
*.svg binary
#*.svg text
*.eps binary

View file

@ -1,68 +1,68 @@
# Find Xerces-C
# The following setings are defined
# XERCESC_ROOT_DIR, the root of the include and lib directory
# XERCESC_INCLUDE_DIR, the full path of the include dir (ADVANCED)
# XERCESC_LIBRARIES, the name of the xerces-c library (ADVANCED)
# Look for a root installation
IF( MSVC )
SET( XERCES_WINDIR C:/Programs/xerces-vc )
ELSE( )
SET( XERCES_WINDIR C:/Programs/xerces )
ENDIF( )
FIND_PATH(XERCESC_ROOT_DIR include/xercesc/parsers/SAXParser.hpp
${XERCES_WINDIR}
"C:/mingw/msys/1.0/local"
"C:/Program Files/CodeSynthesis XSD 3.2"
/usr
/usr/local
"C:/MinGW"
$ENV{CODESYNTH}
DOC "The root of an installed xerces-c installation"
)
# try to find the header
FIND_PATH(XERCESC_INCLUDE_DIR xercesc/parsers/SAXParser.hpp
${XERCESC_ROOT_DIR}/include
/usr/include
/usr/local/include
)
# Find the library
FIND_LIBRARY(XERCESC_LIBRARY
NAMES xerces-c xerces-c_3
PATHS
${XERCESC_ROOT_DIR}/lib
${XERCESC_ROOT_DIR}/lib/vc-9.0
${XERCESC_ROOT_DIR}/lib64/vc-9.0
/usr/lib
/usr/local/lib
DOC "The name of the xerces-c library"
)
IF (XERCESC_ROOT_DIR)
IF (XERCESC_INCLUDE_DIR AND XERCESC_LIBRARY)
SET (XERCESC_FOUND TRUE)
SET (XERCESC_LIBRARIES "${XERCESC_LIBRARY}")
# FIXME: There should be a better way of handling this?
# FIXME: How can we test to see if the lib dir isn't
# FIXME: one of the default dirs?
LINK_DIRECTORIES(${XERCESC_ROOT_DIR}/lib)
ENDIF (XERCESC_INCLUDE_DIR AND XERCESC_LIBRARY)
ENDIF (XERCESC_ROOT_DIR)
IF (XERCESC_FOUND)
IF (NOT XERCESC_FIND_QUIETLY)
MESSAGE (STATUS " found xerces-c: ${XERCESC_LIBRARY}")
ENDIF (NOT XERCESC_FIND_QUIETLY)
ELSE (XERCESC_FOUND)
IF (XERCESC_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find Xerces-C")
ENDIF (XERCESC_FIND_REQUIRED)
ENDIF (XERCESC_FOUND)
MARK_AS_ADVANCED(
XERCESC_INCLUDE_DIR
XERCESC_LIBRARY
# Find Xerces-C
# The following setings are defined
# XERCESC_ROOT_DIR, the root of the include and lib directory
# XERCESC_INCLUDE_DIR, the full path of the include dir (ADVANCED)
# XERCESC_LIBRARIES, the name of the xerces-c library (ADVANCED)
# Look for a root installation
IF( MSVC )
SET( XERCES_WINDIR C:/Programs/xerces-vc )
ELSE( )
SET( XERCES_WINDIR C:/Programs/xerces )
ENDIF( )
FIND_PATH(XERCESC_ROOT_DIR include/xercesc/parsers/SAXParser.hpp
${XERCES_WINDIR}
"C:/mingw/msys/1.0/local"
"C:/Program Files/CodeSynthesis XSD 3.2"
/usr
/usr/local
"C:/MinGW"
$ENV{CODESYNTH}
DOC "The root of an installed xerces-c installation"
)
# try to find the header
FIND_PATH(XERCESC_INCLUDE_DIR xercesc/parsers/SAXParser.hpp
${XERCESC_ROOT_DIR}/include
/usr/include
/usr/local/include
)
# Find the library
FIND_LIBRARY(XERCESC_LIBRARY
NAMES xerces-c xerces-c_3
PATHS
${XERCESC_ROOT_DIR}/lib
${XERCESC_ROOT_DIR}/lib/vc-9.0
${XERCESC_ROOT_DIR}/lib64/vc-9.0
/usr/lib
/usr/local/lib
DOC "The name of the xerces-c library"
)
IF (XERCESC_ROOT_DIR)
IF (XERCESC_INCLUDE_DIR AND XERCESC_LIBRARY)
SET (XERCESC_FOUND TRUE)
SET (XERCESC_LIBRARIES "${XERCESC_LIBRARY}")
# FIXME: There should be a better way of handling this?
# FIXME: How can we test to see if the lib dir isn't
# FIXME: one of the default dirs?
LINK_DIRECTORIES(${XERCESC_ROOT_DIR}/lib)
ENDIF (XERCESC_INCLUDE_DIR AND XERCESC_LIBRARY)
ENDIF (XERCESC_ROOT_DIR)
IF (XERCESC_FOUND)
IF (NOT XERCESC_FIND_QUIETLY)
MESSAGE (STATUS " found xerces-c: ${XERCESC_LIBRARY}")
ENDIF (NOT XERCESC_FIND_QUIETLY)
ELSE (XERCESC_FOUND)
IF (XERCESC_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find Xerces-C")
ENDIF (XERCESC_FIND_REQUIRED)
ENDIF (XERCESC_FOUND)
MARK_AS_ADVANCED(
XERCESC_INCLUDE_DIR
XERCESC_LIBRARY
)

View file

@ -1 +1 @@
IDI_ICON1 ICON DISCARDABLE "icon.ico"
IDI_ICON1 ICON DISCARDABLE "icon.ico"

View file

@ -1,190 +1,190 @@
/*
_____________________________________________________________________________
File Association
_____________________________________________________________________________
Based on code taken from http://nsis.sourceforge.net/File_Association
Usage in script:
1. !include "FileAssociation.nsh"
2. [Section|Function]
${FileAssociationFunction} "Param1" "Param2" "..." $var
[SectionEnd|FunctionEnd]
FileAssociationFunction=[RegisterExtension|UnRegisterExtension]
_____________________________________________________________________________
${RegisterExtension} "[executable]" "[extension]" "[description]"
"[executable]" ; executable which opens the file format
;
"[extension]" ; extension, which represents the file format to open
;
"[description]" ; description for the extension. This will be display in Windows Explorer.
;
${UnRegisterExtension} "[extension]" "[description]"
"[extension]" ; extension, which represents the file format to open
;
"[description]" ; description for the extension. This will be display in Windows Explorer.
;
_____________________________________________________________________________
Macros
_____________________________________________________________________________
Change log window verbosity (default: 3=no script)
Example:
!include "FileAssociation.nsh"
!insertmacro RegisterExtension
${FileAssociation_VERBOSE} 4 # all verbosity
!insertmacro UnRegisterExtension
${FileAssociation_VERBOSE} 3 # no script
*/
!ifndef FileAssociation_INCLUDED
!define FileAssociation_INCLUDED
!include Util.nsh
!verbose push
!verbose 3
!ifndef _FileAssociation_VERBOSE
!define _FileAssociation_VERBOSE 3
!endif
!verbose ${_FileAssociation_VERBOSE}
!define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE`
!verbose pop
!macro FileAssociation_VERBOSE _VERBOSE
!verbose push
!verbose 3
!undef _FileAssociation_VERBOSE
!define _FileAssociation_VERBOSE ${_VERBOSE}
!verbose pop
!macroend
!macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Push `${_DESCRIPTION}`
Push `${_EXTENSION}`
Push `${_EXECUTABLE}`
${CallArtificialFunction} RegisterExtension_
!verbose pop
!macroend
!macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Push `${_EXTENSION}`
Push `${_DESCRIPTION}`
${CallArtificialFunction} UnRegisterExtension_
!verbose pop
!macroend
!define RegisterExtension `!insertmacro RegisterExtensionCall`
!define un.RegisterExtension `!insertmacro RegisterExtensionCall`
!macro RegisterExtension
!macroend
!macro un.RegisterExtension
!macroend
!macro RegisterExtension_
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Exch $R2 ;exe
Exch
Exch $R1 ;ext
Exch
Exch 2
Exch $R0 ;desc
Exch 2
Push $0
Push $1
ReadRegStr $1 HKCR $R1 "" ; read current file association
StrCmp "$1" "" NoBackup ; is it empty
StrCmp "$1" "$R0" NoBackup ; is it our own
WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value
NoBackup:
WriteRegStr HKCR $R1 "" "$R0" ; set our file association
ReadRegStr $0 HKCR $R0 ""
StrCmp $0 "" 0 Skip
WriteRegStr HKCR "$R0" "" "$R0"
WriteRegStr HKCR "$R0\shell" "" "open"
WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0"
Skip:
WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"'
WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0"
WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"'
Pop $1
Pop $0
Pop $R2
Pop $R1
Pop $R0
!verbose pop
!macroend
!define UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
!define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
!macro UnRegisterExtension
!macroend
!macro un.UnRegisterExtension
!macroend
!macro UnRegisterExtension_
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Exch $R1 ;desc
Exch
Exch $R0 ;ext
Exch
Push $0
Push $1
ReadRegStr $1 HKCR $R0 ""
StrCmp $1 $R1 0 NoOwn ; only do this if we own it
ReadRegStr $1 HKCR $R0 "backup_val"
StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key
DeleteRegKey HKCR $R0
Goto NoOwn
Restore:
WriteRegStr HKCR $R0 "" $1
DeleteRegValue HKCR $R0 "backup_val"
DeleteRegKey HKCR $R1 ;Delete key with association name settings
NoOwn:
Pop $1
Pop $0
Pop $R1
Pop $R0
!verbose pop
!macroend
/*
_____________________________________________________________________________
File Association
_____________________________________________________________________________
Based on code taken from http://nsis.sourceforge.net/File_Association
Usage in script:
1. !include "FileAssociation.nsh"
2. [Section|Function]
${FileAssociationFunction} "Param1" "Param2" "..." $var
[SectionEnd|FunctionEnd]
FileAssociationFunction=[RegisterExtension|UnRegisterExtension]
_____________________________________________________________________________
${RegisterExtension} "[executable]" "[extension]" "[description]"
"[executable]" ; executable which opens the file format
;
"[extension]" ; extension, which represents the file format to open
;
"[description]" ; description for the extension. This will be display in Windows Explorer.
;
${UnRegisterExtension} "[extension]" "[description]"
"[extension]" ; extension, which represents the file format to open
;
"[description]" ; description for the extension. This will be display in Windows Explorer.
;
_____________________________________________________________________________
Macros
_____________________________________________________________________________
Change log window verbosity (default: 3=no script)
Example:
!include "FileAssociation.nsh"
!insertmacro RegisterExtension
${FileAssociation_VERBOSE} 4 # all verbosity
!insertmacro UnRegisterExtension
${FileAssociation_VERBOSE} 3 # no script
*/
!ifndef FileAssociation_INCLUDED
!define FileAssociation_INCLUDED
!include Util.nsh
!verbose push
!verbose 3
!ifndef _FileAssociation_VERBOSE
!define _FileAssociation_VERBOSE 3
!endif
!verbose ${_FileAssociation_VERBOSE}
!define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE`
!verbose pop
!macro FileAssociation_VERBOSE _VERBOSE
!verbose push
!verbose 3
!undef _FileAssociation_VERBOSE
!define _FileAssociation_VERBOSE ${_VERBOSE}
!verbose pop
!macroend
!macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Push `${_DESCRIPTION}`
Push `${_EXTENSION}`
Push `${_EXECUTABLE}`
${CallArtificialFunction} RegisterExtension_
!verbose pop
!macroend
!macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Push `${_EXTENSION}`
Push `${_DESCRIPTION}`
${CallArtificialFunction} UnRegisterExtension_
!verbose pop
!macroend
!define RegisterExtension `!insertmacro RegisterExtensionCall`
!define un.RegisterExtension `!insertmacro RegisterExtensionCall`
!macro RegisterExtension
!macroend
!macro un.RegisterExtension
!macroend
!macro RegisterExtension_
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Exch $R2 ;exe
Exch
Exch $R1 ;ext
Exch
Exch 2
Exch $R0 ;desc
Exch 2
Push $0
Push $1
ReadRegStr $1 HKCR $R1 "" ; read current file association
StrCmp "$1" "" NoBackup ; is it empty
StrCmp "$1" "$R0" NoBackup ; is it our own
WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value
NoBackup:
WriteRegStr HKCR $R1 "" "$R0" ; set our file association
ReadRegStr $0 HKCR $R0 ""
StrCmp $0 "" 0 Skip
WriteRegStr HKCR "$R0" "" "$R0"
WriteRegStr HKCR "$R0\shell" "" "open"
WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0"
Skip:
WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"'
WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0"
WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"'
Pop $1
Pop $0
Pop $R2
Pop $R1
Pop $R0
!verbose pop
!macroend
!define UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
!define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
!macro UnRegisterExtension
!macroend
!macro un.UnRegisterExtension
!macroend
!macro UnRegisterExtension_
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Exch $R1 ;desc
Exch
Exch $R0 ;ext
Exch
Push $0
Push $1
ReadRegStr $1 HKCR $R0 ""
StrCmp $1 $R1 0 NoOwn ; only do this if we own it
ReadRegStr $1 HKCR $R0 "backup_val"
StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key
DeleteRegKey HKCR $R0
Goto NoOwn
Restore:
WriteRegStr HKCR $R0 "" $1
DeleteRegValue HKCR $R0 "backup_val"
DeleteRegKey HKCR $R1 ;Delete key with association name settings
NoOwn:
Pop $1
Pop $0
Pop $R1
Pop $R0
!verbose pop
!macroend
!endif # !FileAssociation_INCLUDED

View file

@ -1,12 +1,12 @@
Copyright © 2011-2016 OpenTX team
OpenTX Companion is based on code named eePe by author - Erez Raviv <erezraviv@gmail.com>
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software.
Copyright © 2011-2016 OpenTX team
OpenTX Companion is based on code named eePe by author - Erez Raviv <erezraviv@gmail.com>
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any distribution.

View file

@ -1,340 +1,340 @@
local VALUE = 0
local COMBO = 1
local COLUMN_2 = 300
local edit = false
local page = 1
local current = 1
local refreshState = 0
local refreshIndex = 0
local calibrationState = 0
local pageOffset = 0
local calibrationStep = 0
local pages = {}
local fields = {}
local modifications = {}
local wingBitmaps = {}
local mountBitmaps = {}
local calibBitmaps = {}
local configFields = {
{"Wing type:", COMBO, 0x80, nil, { "Normal", "Delta", "VTail" } },
{"Mounting type:", COMBO, 0x81, nil, { "Horz", "Horz rev.", "Vert", "Vert rev." } },
}
local calibrationPositions = { "up", "down", "left", "right", "forward", "back" }
local wingBitmapsFile = {"img/plane_b.png", "img/delta_b.png", "img/planev_b.png"}
local mountBitmapsFile = {"img/up.png", "img/down.png", "img/vert.png", "img/vert-r.png"}
local calibBitmapsFile = {"img/up.png", "img/down.png", "img/left.png", "img/right.png", "img/forward.png", "img/back.png"}
local settingsFields = {
{"S6R functions:", COMBO, 0x9C, nil, { "Disable", "Enable" } },
{"CH5 mode:", COMBO, 0xA8, nil, { "AIL2", "AUX1" } },
{"CH6 mode:", COMBO, 0xA9, nil, { "ELE2", "AUX2" } },
{"AIL direction:", COMBO, 0x82, nil, { "Normal", "Invers" }, { 255, 0 } },
{"ELE direction:", COMBO, 0x83, nil, { "Normal", "Invers" }, { 255, 0 } },
{"RUD direction:", COMBO, 0x84, nil, { "Normal", "Invers" }, { 255, 0 } },
{"AIL2 direction:", COMBO, 0x9A, nil, { "Normal", "Invers" }, { 255, 0 } },
{"ELE2 direction:", COMBO, 0x9B, nil, { "Normal", "Invers" }, { 255, 0 } },
{"AIL stabilize gain:", VALUE, 0x85, nil, 0, 200, "%"},
{"ELE stabilize gain:", VALUE, 0x86, nil, 0, 200, "%"},
{"RUD stabilize gain:", VALUE, 0x87, nil, 0, 200, "%"},
{"AIL auto level gain:", VALUE, 0x88, nil, 0, 200, "%"},
{"ELE auto level gain:", VALUE, 0x89, nil, 0, 200, "%"},
{"ELE upright gain:", VALUE, 0x8C, nil, 0, 200, "%"},
{"RUD upright gain:", VALUE, 0x8D, nil, 0, 200, "%"},
{"AIL crab gain:", VALUE, 0x8E, nil, 0, 200, "%"},
{"RUD crab gain:", VALUE, 0x90, nil, 0, 200, "%"},
{"AIL auto angle offset:", VALUE, 0x91, nil, -20, 20, "%", 0x6C},
{"ELE auto angle offset:", VALUE, 0x92, nil, -20, 20, "%", 0x6C},
{"ELE upright angle offset:", VALUE, 0x95, nil, -20, 20, "%", 0x6C},
{"RUD upright angle offset:", VALUE, 0x96, nil, -20, 20, "%", 0x6C},
{"AIL crab angle offset:", VALUE, 0x97, nil, -20, 20, "%", 0x6C},
{"RUD crab angle offset:", VALUE, 0x99, nil, -20, 20, "%", 0x6C},
}
local calibrationFields = {
{"X:", VALUE, 0x9E, 0, -100, 100, "%"},
{"Y:", VALUE, 0x9F, 0, -100, 100, "%"},
{"Z:", VALUE, 0xA0, 0, -100, 100, "%"}
}
local function drawScreenTitle(title,page, pages)
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR)
end
-- Change display attribute to current field
local function addField(step)
local field = fields[current]
local min, max
if field[2] == VALUE then
min = field[5]
max = field[6]
elseif field[2] == COMBO then
min = 0
max = #(field[5]) - 1
end
if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then
field[4] = field[4] + step
end
end
-- Select the next or previous page
local function selectPage(step)
page = 1 + ((page + step - 1 + #pages) % #pages)
refreshIndex = 0
calibrationStep = 0
pageOffset = 0
end
-- Select the next or previous editable field
local function selectField(step)
current = 1 + ((current + step - 1 + #fields) % #fields)
if current > 7 + pageOffset then
pageOffset = current - 7
elseif current <= pageOffset then
pageOffset = current - 1
end
end
local function drawProgressBar()
local width = (300 * refreshIndex) / #fields
lcd.drawRectangle(100, 10, 300, 6)
lcd.drawFilledRectangle(102, 13, width, 2);
end
-- Redraw the current page
local function redrawFieldsPage(event)
lcd.clear()
drawScreenTitle("S6R", page, #pages)
if refreshIndex < #fields then
drawProgressBar()
end
for index = 1, 10, 1 do
local field = fields[pageOffset+index]
if field == nil then
break
end
local attr = current == (pageOffset+index) and ((edit == true and BLINK or 0) + INVERS) or 0
attr = attr + TEXT_COLOR
lcd.drawText(1, 30+20*index, field[1], TEXT_COLOR)
if field[4] == nil then
lcd.drawText(COLUMN_2, 30+20*index, "---", attr)
else
if field[2] == VALUE then
lcd.drawNumber(COLUMN_2, 30+20*index, field[4], LEFT + attr)
elseif field[2] == COMBO then
if field[4] >= 0 and field[4] < #(field[5]) then
lcd.drawText(COLUMN_2, 30+20*index, field[5][1+field[4]], attr)
end
end
end
end
end
local function telemetryRead(field)
return sportTelemetryPush(0x17, 0x30, 0x0C30, field)
end
local function telemetryWrite(field, value)
return sportTelemetryPush(0x17, 0x31, 0x0C30, field + value*256)
end
local telemetryPopTimeout = 0
local function refreshNext()
if refreshState == 0 then
if calibrationState == 1 then
if telemetryWrite(0x9D, calibrationStep) == true then
refreshState = 1
calibrationState = 2
telemetryPopTimeout = getTime() + 80 -- normal delay is 500ms
end
elseif #modifications > 0 then
telemetryWrite(modifications[1][1], modifications[1][2])
modifications[1] = nil
elseif refreshIndex < #fields then
local field = fields[refreshIndex + 1]
if telemetryRead(field[3]) == true then
refreshState = 1
telemetryPopTimeout = getTime() + 80 -- normal delay is 500ms
end
end
elseif refreshState == 1 then
local physicalId, primId, dataId, value = sportTelemetryPop()
if physicalId == 0x1A and primId == 0x32 and dataId == 0x0C30 then
local fieldId = value % 256
if calibrationState == 2 then
if fieldId == 0x9D then
refreshState = 0
calibrationState = 0
calibrationStep = (calibrationStep + 1) % 7
end
else
local field = fields[refreshIndex + 1]
if fieldId == field[3] then
local value = math.floor(value / 256)
if field[3] >= 0x9E and field[3] <= 0xA0 then
local b1 = value % 256
local b2 = math.floor(value / 256)
value = b1*256 + b2
value = value - bit32.band(value, 0x8000) * 2
end
if field[2] == COMBO and #field == 6 then
for index = 1, #(field[6]), 1 do
if value == field[6][index] then
value = index - 1
break
end
end
elseif field[2] == VALUE and #field == 8 then
value = value - field[8] + field[5]
end
fields[refreshIndex + 1][4] = value
refreshIndex = refreshIndex + 1
refreshState = 0
end
end
elseif getTime() > telemetryPopTimeout then
refreshState = 0
calibrationState = 0
end
end
end
local function updateField(field)
local value = field[4]
if field[2] == COMBO and #field == 6 then
value = field[6][1+value]
elseif field[2] == VALUE and #field == 8 then
value = value + field[8] - field[5]
end
modifications[#modifications+1] = { field[3], value }
end
-- Main
local function runFieldsPage(event)
if event == EVT_EXIT_BREAK then -- exit script
return 2
elseif event == EVT_ENTER_BREAK or event == EVT_ROT_BREAK then -- toggle editing/selecting current field
if fields[current][4] ~= nil then
edit = not edit
if edit == false then
updateField(fields[current])
end
end
elseif edit then
if event == EVT_PLUS_FIRST or event == EVT_ROT_RIGHT or event == EVT_PLUS_REPT then
addField(1)
elseif event == EVT_MINUS_FIRST or event == EVT_ROT_LEFT or event == EVT_MINUS_REPT then
addField(-1)
end
else
if event == EVT_MINUS_FIRST or event == EVT_ROT_RIGHT then
selectField(1)
elseif event == EVT_PLUS_FIRST or event == EVT_ROT_LEFT then
selectField(-1)
end
end
redrawFieldsPage(event)
return 0
end
local function runConfigPage(event)
fields = configFields
local result = runFieldsPage(event)
if fields[1][4] ~= nil then
if wingBitmaps[1 + fields[1][4]] == nil then
wingBitmaps[1 + fields[1][4]] = Bitmap.open(wingBitmapsFile[1 + fields[1][4]])
end
lcd.drawBitmap(wingBitmaps[1 + fields[1][4]], 10, 90)
end
if fields[2][4] ~= nil then
if mountBitmaps[1 + fields[2][4]] == nil then
mountBitmaps[1 + fields[2][4]] = Bitmap.open(mountBitmapsFile[1 + fields[2][4]])
end
lcd.drawBitmap(mountBitmaps[1 + fields[2][4]], 190, 110)
end
return result
end
local function runSettingsPage(event)
fields = settingsFields
return runFieldsPage(event)
end
local function runCalibrationPage(event)
fields = calibrationFields
if refreshIndex == #fields then
refreshIndex = 0
end
lcd.clear()
drawScreenTitle("S6R", page, #pages)
if(calibrationStep < 6) then
local position = calibrationPositions[1 + calibrationStep]
lcd.drawText(100, 50, "Place the S6R in the following position", TEXT_COLOR)
if calibBitmaps[calibrationStep + 1] == nil then
calibBitmaps[calibrationStep + 1] = Bitmap.open(calibBitmapsFile[calibrationStep + 1])
end
lcd.drawBitmap(calibBitmaps[calibrationStep + 1], 200, 70)
for index = 1, 3, 1 do
local field = fields[index]
lcd.drawText(70, 80+20*index, field[1]..":", TEXT_COLOR)
lcd.drawNumber(90, 80+20*index, field[4]/10, LEFT+PREC2)
end
local attr = calibrationState == 0 and INVERS or 0
lcd.drawText(160, 220, "Press [Enter] when ready", attr)
else
lcd.drawText(160, 50, "Calibration completed", 0)
lcd.drawBitmap(Bitmap.open("img/done.bmp"),200, 100)
lcd.drawText(160, 220, "Press [RTN] when ready", attr)
end
if calibrationStep > 6 and (event == EVT_ENTER_BREAK or event == EVT_EXIT_BREAK) then
return 2
elseif event == EVT_ENTER_BREAK then
calibrationState = 1
elseif event == EVT_EXIT_BREAK then
if calibrationStep > 0 then
calibrationStep = 0
end
end
return 0
end
-- Init
local function init()
current, edit, refreshState, refreshIndex = 1, false, 0, 0
pages = {
runConfigPage,
runSettingsPage,
runCalibrationPage
}
end
-- Main
local function run(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
elseif event == EVT_PAGE_BREAK or event == EVT_PAGEDN_FIRST then
selectPage(1)
elseif event == EVT_PAGE_LONG or event == EVT_PAGEUP_FIRST then
killEvents(event);
selectPage(-1)
end
local result = pages[page](event)
refreshNext()
return result
end
return { init=init, run=run }
local VALUE = 0
local COMBO = 1
local COLUMN_2 = 300
local edit = false
local page = 1
local current = 1
local refreshState = 0
local refreshIndex = 0
local calibrationState = 0
local pageOffset = 0
local calibrationStep = 0
local pages = {}
local fields = {}
local modifications = {}
local wingBitmaps = {}
local mountBitmaps = {}
local calibBitmaps = {}
local configFields = {
{"Wing type:", COMBO, 0x80, nil, { "Normal", "Delta", "VTail" } },
{"Mounting type:", COMBO, 0x81, nil, { "Horz", "Horz rev.", "Vert", "Vert rev." } },
}
local calibrationPositions = { "up", "down", "left", "right", "forward", "back" }
local wingBitmapsFile = {"img/plane_b.png", "img/delta_b.png", "img/planev_b.png"}
local mountBitmapsFile = {"img/up.png", "img/down.png", "img/vert.png", "img/vert-r.png"}
local calibBitmapsFile = {"img/up.png", "img/down.png", "img/left.png", "img/right.png", "img/forward.png", "img/back.png"}
local settingsFields = {
{"S6R functions:", COMBO, 0x9C, nil, { "Disable", "Enable" } },
{"CH5 mode:", COMBO, 0xA8, nil, { "AIL2", "AUX1" } },
{"CH6 mode:", COMBO, 0xA9, nil, { "ELE2", "AUX2" } },
{"AIL direction:", COMBO, 0x82, nil, { "Normal", "Invers" }, { 255, 0 } },
{"ELE direction:", COMBO, 0x83, nil, { "Normal", "Invers" }, { 255, 0 } },
{"RUD direction:", COMBO, 0x84, nil, { "Normal", "Invers" }, { 255, 0 } },
{"AIL2 direction:", COMBO, 0x9A, nil, { "Normal", "Invers" }, { 255, 0 } },
{"ELE2 direction:", COMBO, 0x9B, nil, { "Normal", "Invers" }, { 255, 0 } },
{"AIL stabilize gain:", VALUE, 0x85, nil, 0, 200, "%"},
{"ELE stabilize gain:", VALUE, 0x86, nil, 0, 200, "%"},
{"RUD stabilize gain:", VALUE, 0x87, nil, 0, 200, "%"},
{"AIL auto level gain:", VALUE, 0x88, nil, 0, 200, "%"},
{"ELE auto level gain:", VALUE, 0x89, nil, 0, 200, "%"},
{"ELE upright gain:", VALUE, 0x8C, nil, 0, 200, "%"},
{"RUD upright gain:", VALUE, 0x8D, nil, 0, 200, "%"},
{"AIL crab gain:", VALUE, 0x8E, nil, 0, 200, "%"},
{"RUD crab gain:", VALUE, 0x90, nil, 0, 200, "%"},
{"AIL auto angle offset:", VALUE, 0x91, nil, -20, 20, "%", 0x6C},
{"ELE auto angle offset:", VALUE, 0x92, nil, -20, 20, "%", 0x6C},
{"ELE upright angle offset:", VALUE, 0x95, nil, -20, 20, "%", 0x6C},
{"RUD upright angle offset:", VALUE, 0x96, nil, -20, 20, "%", 0x6C},
{"AIL crab angle offset:", VALUE, 0x97, nil, -20, 20, "%", 0x6C},
{"RUD crab angle offset:", VALUE, 0x99, nil, -20, 20, "%", 0x6C},
}
local calibrationFields = {
{"X:", VALUE, 0x9E, 0, -100, 100, "%"},
{"Y:", VALUE, 0x9F, 0, -100, 100, "%"},
{"Z:", VALUE, 0xA0, 0, -100, 100, "%"}
}
local function drawScreenTitle(title,page, pages)
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
lcd.drawText(LCD_W-40, 5, page.."/"..pages, MENU_TITLE_COLOR)
end
-- Change display attribute to current field
local function addField(step)
local field = fields[current]
local min, max
if field[2] == VALUE then
min = field[5]
max = field[6]
elseif field[2] == COMBO then
min = 0
max = #(field[5]) - 1
end
if (step < 0 and field[4] > min) or (step > 0 and field[4] < max) then
field[4] = field[4] + step
end
end
-- Select the next or previous page
local function selectPage(step)
page = 1 + ((page + step - 1 + #pages) % #pages)
refreshIndex = 0
calibrationStep = 0
pageOffset = 0
end
-- Select the next or previous editable field
local function selectField(step)
current = 1 + ((current + step - 1 + #fields) % #fields)
if current > 7 + pageOffset then
pageOffset = current - 7
elseif current <= pageOffset then
pageOffset = current - 1
end
end
local function drawProgressBar()
local width = (300 * refreshIndex) / #fields
lcd.drawRectangle(100, 10, 300, 6)
lcd.drawFilledRectangle(102, 13, width, 2);
end
-- Redraw the current page
local function redrawFieldsPage(event)
lcd.clear()
drawScreenTitle("S6R", page, #pages)
if refreshIndex < #fields then
drawProgressBar()
end
for index = 1, 10, 1 do
local field = fields[pageOffset+index]
if field == nil then
break
end
local attr = current == (pageOffset+index) and ((edit == true and BLINK or 0) + INVERS) or 0
attr = attr + TEXT_COLOR
lcd.drawText(1, 30+20*index, field[1], TEXT_COLOR)
if field[4] == nil then
lcd.drawText(COLUMN_2, 30+20*index, "---", attr)
else
if field[2] == VALUE then
lcd.drawNumber(COLUMN_2, 30+20*index, field[4], LEFT + attr)
elseif field[2] == COMBO then
if field[4] >= 0 and field[4] < #(field[5]) then
lcd.drawText(COLUMN_2, 30+20*index, field[5][1+field[4]], attr)
end
end
end
end
end
local function telemetryRead(field)
return sportTelemetryPush(0x17, 0x30, 0x0C30, field)
end
local function telemetryWrite(field, value)
return sportTelemetryPush(0x17, 0x31, 0x0C30, field + value*256)
end
local telemetryPopTimeout = 0
local function refreshNext()
if refreshState == 0 then
if calibrationState == 1 then
if telemetryWrite(0x9D, calibrationStep) == true then
refreshState = 1
calibrationState = 2
telemetryPopTimeout = getTime() + 80 -- normal delay is 500ms
end
elseif #modifications > 0 then
telemetryWrite(modifications[1][1], modifications[1][2])
modifications[1] = nil
elseif refreshIndex < #fields then
local field = fields[refreshIndex + 1]
if telemetryRead(field[3]) == true then
refreshState = 1
telemetryPopTimeout = getTime() + 80 -- normal delay is 500ms
end
end
elseif refreshState == 1 then
local physicalId, primId, dataId, value = sportTelemetryPop()
if physicalId == 0x1A and primId == 0x32 and dataId == 0x0C30 then
local fieldId = value % 256
if calibrationState == 2 then
if fieldId == 0x9D then
refreshState = 0
calibrationState = 0
calibrationStep = (calibrationStep + 1) % 7
end
else
local field = fields[refreshIndex + 1]
if fieldId == field[3] then
local value = math.floor(value / 256)
if field[3] >= 0x9E and field[3] <= 0xA0 then
local b1 = value % 256
local b2 = math.floor(value / 256)
value = b1*256 + b2
value = value - bit32.band(value, 0x8000) * 2
end
if field[2] == COMBO and #field == 6 then
for index = 1, #(field[6]), 1 do
if value == field[6][index] then
value = index - 1
break
end
end
elseif field[2] == VALUE and #field == 8 then
value = value - field[8] + field[5]
end
fields[refreshIndex + 1][4] = value
refreshIndex = refreshIndex + 1
refreshState = 0
end
end
elseif getTime() > telemetryPopTimeout then
refreshState = 0
calibrationState = 0
end
end
end
local function updateField(field)
local value = field[4]
if field[2] == COMBO and #field == 6 then
value = field[6][1+value]
elseif field[2] == VALUE and #field == 8 then
value = value + field[8] - field[5]
end
modifications[#modifications+1] = { field[3], value }
end
-- Main
local function runFieldsPage(event)
if event == EVT_EXIT_BREAK then -- exit script
return 2
elseif event == EVT_ENTER_BREAK or event == EVT_ROT_BREAK then -- toggle editing/selecting current field
if fields[current][4] ~= nil then
edit = not edit
if edit == false then
updateField(fields[current])
end
end
elseif edit then
if event == EVT_PLUS_FIRST or event == EVT_ROT_RIGHT or event == EVT_PLUS_REPT then
addField(1)
elseif event == EVT_MINUS_FIRST or event == EVT_ROT_LEFT or event == EVT_MINUS_REPT then
addField(-1)
end
else
if event == EVT_MINUS_FIRST or event == EVT_ROT_RIGHT then
selectField(1)
elseif event == EVT_PLUS_FIRST or event == EVT_ROT_LEFT then
selectField(-1)
end
end
redrawFieldsPage(event)
return 0
end
local function runConfigPage(event)
fields = configFields
local result = runFieldsPage(event)
if fields[1][4] ~= nil then
if wingBitmaps[1 + fields[1][4]] == nil then
wingBitmaps[1 + fields[1][4]] = Bitmap.open(wingBitmapsFile[1 + fields[1][4]])
end
lcd.drawBitmap(wingBitmaps[1 + fields[1][4]], 10, 90)
end
if fields[2][4] ~= nil then
if mountBitmaps[1 + fields[2][4]] == nil then
mountBitmaps[1 + fields[2][4]] = Bitmap.open(mountBitmapsFile[1 + fields[2][4]])
end
lcd.drawBitmap(mountBitmaps[1 + fields[2][4]], 190, 110)
end
return result
end
local function runSettingsPage(event)
fields = settingsFields
return runFieldsPage(event)
end
local function runCalibrationPage(event)
fields = calibrationFields
if refreshIndex == #fields then
refreshIndex = 0
end
lcd.clear()
drawScreenTitle("S6R", page, #pages)
if(calibrationStep < 6) then
local position = calibrationPositions[1 + calibrationStep]
lcd.drawText(100, 50, "Place the S6R in the following position", TEXT_COLOR)
if calibBitmaps[calibrationStep + 1] == nil then
calibBitmaps[calibrationStep + 1] = Bitmap.open(calibBitmapsFile[calibrationStep + 1])
end
lcd.drawBitmap(calibBitmaps[calibrationStep + 1], 200, 70)
for index = 1, 3, 1 do
local field = fields[index]
lcd.drawText(70, 80+20*index, field[1]..":", TEXT_COLOR)
lcd.drawNumber(90, 80+20*index, field[4]/10, LEFT+PREC2)
end
local attr = calibrationState == 0 and INVERS or 0
lcd.drawText(160, 220, "Press [Enter] when ready", attr)
else
lcd.drawText(160, 50, "Calibration completed", 0)
lcd.drawBitmap(Bitmap.open("img/done.bmp"),200, 100)
lcd.drawText(160, 220, "Press [RTN] when ready", attr)
end
if calibrationStep > 6 and (event == EVT_ENTER_BREAK or event == EVT_EXIT_BREAK) then
return 2
elseif event == EVT_ENTER_BREAK then
calibrationState = 1
elseif event == EVT_EXIT_BREAK then
if calibrationStep > 0 then
calibrationStep = 0
end
end
return 0
end
-- Init
local function init()
current, edit, refreshState, refreshIndex = 1, false, 0, 0
pages = {
runConfigPage,
runSettingsPage,
runCalibrationPage
}
end
-- Main
local function run(event)
if event == nil then
error("Cannot be run as a model script!")
return 2
elseif event == EVT_PAGE_BREAK or event == EVT_PAGEDN_FIRST then
selectPage(1)
elseif event == EVT_PAGE_LONG or event == EVT_PAGEUP_FIRST then
killEvents(event);
selectPage(-1)
end
local result = pages[page](event)
refreshNext()
return result
end
return { init=init, run=run }

View file

@ -1,176 +1,176 @@
--------------------------------------------------------------
-- Classic snake game
--
-- 2009 Led Lab @PUC-Rio www.eluaproject.net
-- Dado Sutter
-- Ives Negreiros
-- To Benjamin
---------------------------------------------------------------
local xMax = math.floor( LCD_W / 6 ) - 1
local yMax = math.floor( LCD_H / 8 ) - 1
local game_map = {}
local Head = {}
local Tail = {}
local highscore = 0
local size = 3
Tail.x = 1
Tail.y = 1
Head.x = Tail.x + ( size - 1 )
Head.y = Tail.y
local Food = {}
Food.x = false
Food.y = false
Head.dx = 1
Head.dy = 0
Tail.dx = Head.dx
Tail.dy = Head.dy
local direction = "right"
local score = 0
local function create_food()
Food.x, Food.y = math.random( xMax - 1), math.random( yMax - 1)
while game_map[ Food.x ][ Food.y ] do
Food.x, Food.y = math.random( xMax - 1 ), math.random( yMax - 1 )
end
game_map[ Food.x ][ Food.y ] = "food"
lcd.drawText( Food.x * 6, Food.y * 8+2, "@", 0 )
end
local function eat_food()
playFile("/SCRIPTS/snake.wav")
lcd.drawText( Head.x * 6, Head.y * 8, " ", 0 )
game_map[ Head.x ][ Head.y ] = nil
create_food()
score = score + 1
end
local function check_collision()
if Head.x < 0 or Head.x > xMax then
return true
elseif Head.y < 0 or Head.y > yMax then
return true
elseif ( ( game_map[ Head.x ][ Head.y ] ) and ( game_map[ Head.x ][ Head.y ] ~= "food" ) ) then
return true
end
return false
end
local function move()
if game_map[ Tail.x ][ Tail.y ] == "right" then
Tail.dx = 1
Tail.dy = 0
elseif game_map[ Tail.x ][ Tail.y ] == "left" then
Tail.dx = -1
Tail.dy = 0
elseif game_map[ Tail.x ][ Tail.y ] == "up" then
Tail.dx = 0
Tail.dy = -1
elseif game_map[ Tail.x ][ Tail.y ] == "down" then
Tail.dx = 0
Tail.dy = 1
end
game_map[ Head.x ][ Head.y ] = direction
Head.x = Head.x + Head.dx
Head.y = Head.y + Head.dy
if Head.x < 0 or Head.x > xMax or Head.y < 0 or Head.y > yMax then
return
elseif game_map[ Head.x ][ Head.y ] == "food" then
eat_food()
else
lcd.drawText(Tail.x * 6, Tail.y * 8, " ", 16)
game_map[ Tail.x ][ Tail.y ] = nil
Tail.x = Tail.x + Tail.dx
Tail.y = Tail.y + Tail.dy
end
lcd.drawText(Head.x * 6, Head.y * 8, "*", 0)
end
local function init()
food = false
lcd.clear()
size = 3
score = 0
Tail.x = 1
Tail.y = 1
Head.x = Tail.x + ( size - 1 )
Head.y = Tail.y
Head.dx = 1
Head.dy = 0
Tail.dx = Head.dx
Tail.dy = Head.dy
direction = "right"
for i = 0, xMax, 1 do
game_map[ i ] = {}
end
for i = 0, size - 1, 1 do
game_map[ Tail.x + ( i * Tail.dx ) ][ Tail.y + ( i * Tail.dy ) ] = direction
lcd.drawText( ( Tail.x + ( i * Tail.dx ) ) * 6, ( Tail.y + ( i * Tail.dy ) ) * 8, "*", 0 )
end
create_food()
end
local snakeCounter = 0
local function run(event)
if event == nil then
raise("Cannot be run as a model script!")
end
if event == EVT_EXIT_BREAK then
return 2
end
snakeCounter = snakeCounter + 1
if snakeCounter < 30 then
return 0
end
snakeCounter = 0
local dir = direction
if getValue('rud') > 100 and direction ~= "left" then
dir = "right"
Head.dx = 1
Head.dy = 0
end
if getValue('rud') < -100 and direction ~= "right" then
dir = "left"
Head.dx = -1
Head.dy = 0
end
if getValue('ele') > 100 and direction ~= "down" then
dir = "up"
Head.dx = 0
Head.dy = -1
end
if getValue('ele') < -100 and direction ~= "up" then
dir = "down"
Head.dx = 0
Head.dy = 1
end
direction = dir
move()
lcd.refresh()
if check_collision() then
return 1
end
return 0
end
return { init=init, run=run }
--------------------------------------------------------------
-- Classic snake game
--
-- 2009 Led Lab @PUC-Rio www.eluaproject.net
-- Dado Sutter
-- Ives Negreiros
-- To Benjamin
---------------------------------------------------------------
local xMax = math.floor( LCD_W / 6 ) - 1
local yMax = math.floor( LCD_H / 8 ) - 1
local game_map = {}
local Head = {}
local Tail = {}
local highscore = 0
local size = 3
Tail.x = 1
Tail.y = 1
Head.x = Tail.x + ( size - 1 )
Head.y = Tail.y
local Food = {}
Food.x = false
Food.y = false
Head.dx = 1
Head.dy = 0
Tail.dx = Head.dx
Tail.dy = Head.dy
local direction = "right"
local score = 0
local function create_food()
Food.x, Food.y = math.random( xMax - 1), math.random( yMax - 1)
while game_map[ Food.x ][ Food.y ] do
Food.x, Food.y = math.random( xMax - 1 ), math.random( yMax - 1 )
end
game_map[ Food.x ][ Food.y ] = "food"
lcd.drawText( Food.x * 6, Food.y * 8+2, "@", 0 )
end
local function eat_food()
playFile("/SCRIPTS/snake.wav")
lcd.drawText( Head.x * 6, Head.y * 8, " ", 0 )
game_map[ Head.x ][ Head.y ] = nil
create_food()
score = score + 1
end
local function check_collision()
if Head.x < 0 or Head.x > xMax then
return true
elseif Head.y < 0 or Head.y > yMax then
return true
elseif ( ( game_map[ Head.x ][ Head.y ] ) and ( game_map[ Head.x ][ Head.y ] ~= "food" ) ) then
return true
end
return false
end
local function move()
if game_map[ Tail.x ][ Tail.y ] == "right" then
Tail.dx = 1
Tail.dy = 0
elseif game_map[ Tail.x ][ Tail.y ] == "left" then
Tail.dx = -1
Tail.dy = 0
elseif game_map[ Tail.x ][ Tail.y ] == "up" then
Tail.dx = 0
Tail.dy = -1
elseif game_map[ Tail.x ][ Tail.y ] == "down" then
Tail.dx = 0
Tail.dy = 1
end
game_map[ Head.x ][ Head.y ] = direction
Head.x = Head.x + Head.dx
Head.y = Head.y + Head.dy
if Head.x < 0 or Head.x > xMax or Head.y < 0 or Head.y > yMax then
return
elseif game_map[ Head.x ][ Head.y ] == "food" then
eat_food()
else
lcd.drawText(Tail.x * 6, Tail.y * 8, " ", 16)
game_map[ Tail.x ][ Tail.y ] = nil
Tail.x = Tail.x + Tail.dx
Tail.y = Tail.y + Tail.dy
end
lcd.drawText(Head.x * 6, Head.y * 8, "*", 0)
end
local function init()
food = false
lcd.clear()
size = 3
score = 0
Tail.x = 1
Tail.y = 1
Head.x = Tail.x + ( size - 1 )
Head.y = Tail.y
Head.dx = 1
Head.dy = 0
Tail.dx = Head.dx
Tail.dy = Head.dy
direction = "right"
for i = 0, xMax, 1 do
game_map[ i ] = {}
end
for i = 0, size - 1, 1 do
game_map[ Tail.x + ( i * Tail.dx ) ][ Tail.y + ( i * Tail.dy ) ] = direction
lcd.drawText( ( Tail.x + ( i * Tail.dx ) ) * 6, ( Tail.y + ( i * Tail.dy ) ) * 8, "*", 0 )
end
create_food()
end
local snakeCounter = 0
local function run(event)
if event == nil then
raise("Cannot be run as a model script!")
end
if event == EVT_EXIT_BREAK then
return 2
end
snakeCounter = snakeCounter + 1
if snakeCounter < 30 then
return 0
end
snakeCounter = 0
local dir = direction
if getValue('rud') > 100 and direction ~= "left" then
dir = "right"
Head.dx = 1
Head.dy = 0
end
if getValue('rud') < -100 and direction ~= "right" then
dir = "left"
Head.dx = -1
Head.dy = 0
end
if getValue('ele') > 100 and direction ~= "down" then
dir = "up"
Head.dx = 0
Head.dy = -1
end
if getValue('ele') < -100 and direction ~= "up" then
dir = "down"
Head.dx = 0
Head.dy = 1
end
direction = dir
move()
lcd.refresh()
if check_collision() then
return 1
end
return 0
end
return { init=init, run=run }

View file

@ -1,375 +1,375 @@
-- Delta Wizard pages
local ENGINE_PAGE = 0
local ELEVONS_PAGE = 1
local RUDDER_PAGE = 2
local CONFIRMATION_PAGE = 3
-- Navigation variables
local page = ENGINE_PAGE
local dirty = true
local edit = false
local field = 0
local fieldsMax = 0
-- Model settings
local engineMode = 1
local thrCH1 = 0
local elevCH1 = 0
local elevCH2 = 0
local elevonsMode = 0
local rudderMode = 0
local rudCH1 = 0
local servoPage = nil
-- Common functions
local lastBlink = 0
local function blinkChanged()
local time = getTime() % 128
local blink = (time - time % 64) / 64
if blink ~= lastBlink then
lastBlink = blink
return true
else
return false
end
end
local function fieldIncDec(event, value, max, force)
if edit or force==true then
if event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT then
value = (value + max)
dirty = true
elseif event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT then
value = (value + max + 2)
dirty = true
end
value = (value % (max+1))
end
return value
end
local function valueIncDec(event, value, min, max)
if edit then
if event == EVT_PLUS_FIRST or event == EVT_PLUS_REPT or event == EVT_ROT_RIGHT then
if value < max then
value = (value + 1)
dirty = true
end
elseif event == EVT_MINUS_FIRST or event == EVT_MINUS_REPT or event == EVT_ROT_LEFT then
if value > min then
value = (value - 1)
dirty = true
end
end
end
return value
end
local function navigate(event, fieldMax, prevPage, nextPage)
if event == EVT_ENTER_BREAK then
edit = not edit
dirty = true
elseif edit then
if event == EVT_EXIT_BREAK then
edit = false
dirty = true
elseif not dirty then
dirty = blinkChanged()
end
else
if event == EVT_PAGE_BREAK then
page = nextPage
field = 0
dirty = true
elseif event == EVT_PAGE_LONG then
page = prevPage
field = 0
killEvents(event);
dirty = true
else
field = fieldIncDec(event, field, fieldMax, true)
end
end
end
local function getFieldFlags(position)
flags = 0
if field == position then
flags = INVERS
if edit then
flags = INVERS + BLINK
end
end
return flags
end
local function channelIncDec(event, value)
if not edit and event==EVT_MENU_BREAK then
servoPage = value
dirty = true
else
value = valueIncDec(event, value, 0, 15)
end
return value
end
-- Init function
local function init()
rudCH1 = defaultChannel(0)
thrCH1 = defaultChannel(2)
elevCH1 = defaultChannel(1)
elevCH2 = defaultChannel(3)
end
-- Engine Menu
local engineModeItems = {"No", "Yes..."}
local function drawEngineMenu()
lcd.clear()
lcd.drawText(1, 0, "Has your model got an engine?", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, engineModeItems, engineMode, getFieldFlags(0))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
if engineMode == 0 then
-- No engine
lcd.drawPixmap(132, 8, "engine-0.bmp")
fieldsMax = 0
else
-- 1 channel
lcd.drawPixmap(132, 8, "engine-1.bmp")
lcd.drawText(25, LCD_H-16, "Assign channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(151, LCD_H-8, MIXSRC_CH1+thrCH1, getFieldFlags(1))
fieldsMax = 1
end
end
local function engineMenu(event)
if dirty then
dirty = false
drawEngineMenu()
end
navigate(event, fieldsMax, page, page+1)
if field==0 then
engineMode = fieldIncDec(event, engineMode, 1)
elseif field==1 then
thrCH1 = channelIncDec(event, thrCH1)
end
end
-- Elevons Menu
local elevonsModeItems = {"2 Channels..."}
local function drawElevonsMenu()
lcd.clear()
lcd.drawText(1, 0, "Select elevon channnels", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, elevonsModeItems, elevonsMode, 0)
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(110, 9, "elevons.bmp")
lcd.drawText(20, LCD_H-16, "Assign channels", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(116, LCD_H-8, MIXSRC_CH1+elevCH1, getFieldFlags(0))
lcd.drawSource(175, LCD_H-8, MIXSRC_CH1+elevCH2, getFieldFlags(1))
fieldsMax = 1
end
local function elevonsMenu(event)
if dirty then
dirty = false
drawElevonsMenu()
end
navigate(event, fieldsMax, page-1, page+1)
if field==0 then
elevCH1 = channelIncDec(event, elevCH1)
elseif field==1 then
elevCH2 = channelIncDec(event, elevCH2)
end
end
-- Rudder menu
local rudderModeItems = {"No", "Yes..."}
local function drawRudderMenu()
lcd.clear()
lcd.drawText(1, 0, "Has your model got a rudder?", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, rudderModeItems, rudderMode, getFieldFlags(0))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
if rudderMode == 0 then
-- No rudder
lcd.drawPixmap(109, 14, "drudder-0.bmp")
fieldsMax = 0
else
-- 1 channel
lcd.drawPixmap(109, 14, "drudder-1.bmp")
lcd.drawText(25, LCD_H-16, "Assign channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(190, LCD_H-55, MIXSRC_CH1+rudCH1, getFieldFlags(1))
fieldsMax = 1
end
end
local function rudderMenu(event)
if dirty then
dirty = false
drawRudderMenu()
end
navigate(event, fieldsMax, page-1, page+1)
if field==0 then
rudderMode = fieldIncDec(event, rudderMode, 1)
elseif field==1 then
rudCH1 = channelIncDec(event, rudCH1)
end
end
-- Servo (limits) Menu
local function drawServoMenu(limits)
lcd.clear()
lcd.drawSource(1, 0, MIXSRC_CH1+servoPage, 0)
lcd.drawText(25, 0, "servo min/max/center/direction?", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawLine(LCD_W/2-1, 8, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawPixmap(122, 8, "servo.bmp")
lcd.drawNumber(140, 35, limits.min, PREC1+getFieldFlags(0));
lcd.drawNumber(205, 35, limits.max, PREC1+getFieldFlags(1));
lcd.drawNumber(170, 9, limits.offset, PREC1+getFieldFlags(2));
if limits.revert == 0 then
lcd.drawText(129, 50, "\126", getFieldFlags(3));
else
lcd.drawText(129, 50, "\127", getFieldFlags(3));
end
fieldsMax = 3
end
local function servoMenu(event)
local limits = model.getOutput(servoPage)
if dirty then
dirty = false
drawServoMenu(limits)
end
navigate(event, fieldsMax, page, page)
if edit then
if field==0 then
limits.min = valueIncDec(event, limits.min, -1000, 0)
elseif field==1 then
limits.max = valueIncDec(event, limits.max, 0, 1000)
elseif field==2 then
limits.offset = valueIncDec(event, limits.offset, -1000, 1000)
elseif field==3 then
limits.revert = fieldIncDec(event, limits.revert, 1)
end
model.setOutput(servoPage, limits)
elseif event == EVT_EXIT_BREAK then
servoPage = nil
dirty = true
end
end
-- Confirmation Menu
local function addMix(channel, input, name, weight, index)
local mix = { source=input, name=name }
if weight ~= nil then
mix.weight = weight
end
if index == nil then
index = 0
end
model.insertMix(channel, index, mix)
end
local function applySettings()
model.defaultInputs()
model.deleteMixes()
if engineMode == 1 then
addMix(thrCH1, MIXSRC_FIRST_INPUT+defaultChannel(2), "Engine")
end
addMix(elevCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "Elev1-E", 50)
addMix(elevCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "Elev1-A", 50, 1)
addMix(elevCH2, MIXSRC_FIRST_INPUT+defaultChannel(1), "Elev2-E", 50)
addMix(elevCH2, MIXSRC_FIRST_INPUT+defaultChannel(3), "Elev2-A", -50, 1)
if rudderMode == 1 then
addMix(rudCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "Rudder")
end
end
local function drawNextLine(x, y, label, channel)
lcd.drawText(x, y, label, 0);
lcd.drawSource(x+52, y, MIXSRC_CH1+channel, 0)
y = y + 8
if y > 50 then
y = 12
x = 120
end
return x, y
end
local function drawConfirmationMenu()
local x = 22
local y = 12
lcd.clear()
lcd.drawText(48, 1, "Ready to go?", 0);
lcd.drawFilledRectangle(0, 0, LCD_W, 9, 0)
if engineMode == 1 then
x, y = drawNextLine(x, y, "Throttle:", thrCH1)
end
x, y = drawNextLine(x, y, "Elevons:", elevCH1)
x, y = drawNextLine(x, y, "Elevons:", elevCH2)
if rudderMode == 1 then
drawNextLine(x, y, "Rudder:", rudCH1)
end
lcd.drawText(48, LCD_H-8, "[Enter Long] to confirm", 0);
lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0)
lcd.drawPixmap(LCD_W-18, 0, "confirm-tick.bmp")
lcd.drawPixmap(0, LCD_H-17, "confirm-plane.bmp")
fieldsMax = 0
end
local function confirmationMenu(event)
if dirty then
dirty = false
drawConfirmationMenu()
end
navigate(event, fieldsMax, RUDDER_PAGE, page)
if event == EVT_EXIT_BREAK then
return 2
elseif event == EVT_ENTER_LONG then
killEvents(event)
applySettings()
return 2
else
return 0
end
end
-- Main
local function run(event)
if event == nil then
error("Cannot be run as a model script!")
end
if servoPage ~= nil then
servoMenu(event)
elseif page == ENGINE_PAGE then
engineMenu(event)
elseif page == ELEVONS_PAGE then
elevonsMenu(event)
elseif page == RUDDER_PAGE then
rudderMenu(event)
elseif page == CONFIRMATION_PAGE then
return confirmationMenu(event)
end
return 0
end
return { init=init, run=run }
-- Delta Wizard pages
local ENGINE_PAGE = 0
local ELEVONS_PAGE = 1
local RUDDER_PAGE = 2
local CONFIRMATION_PAGE = 3
-- Navigation variables
local page = ENGINE_PAGE
local dirty = true
local edit = false
local field = 0
local fieldsMax = 0
-- Model settings
local engineMode = 1
local thrCH1 = 0
local elevCH1 = 0
local elevCH2 = 0
local elevonsMode = 0
local rudderMode = 0
local rudCH1 = 0
local servoPage = nil
-- Common functions
local lastBlink = 0
local function blinkChanged()
local time = getTime() % 128
local blink = (time - time % 64) / 64
if blink ~= lastBlink then
lastBlink = blink
return true
else
return false
end
end
local function fieldIncDec(event, value, max, force)
if edit or force==true then
if event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT then
value = (value + max)
dirty = true
elseif event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT then
value = (value + max + 2)
dirty = true
end
value = (value % (max+1))
end
return value
end
local function valueIncDec(event, value, min, max)
if edit then
if event == EVT_PLUS_FIRST or event == EVT_PLUS_REPT or event == EVT_ROT_RIGHT then
if value < max then
value = (value + 1)
dirty = true
end
elseif event == EVT_MINUS_FIRST or event == EVT_MINUS_REPT or event == EVT_ROT_LEFT then
if value > min then
value = (value - 1)
dirty = true
end
end
end
return value
end
local function navigate(event, fieldMax, prevPage, nextPage)
if event == EVT_ENTER_BREAK then
edit = not edit
dirty = true
elseif edit then
if event == EVT_EXIT_BREAK then
edit = false
dirty = true
elseif not dirty then
dirty = blinkChanged()
end
else
if event == EVT_PAGE_BREAK then
page = nextPage
field = 0
dirty = true
elseif event == EVT_PAGE_LONG then
page = prevPage
field = 0
killEvents(event);
dirty = true
else
field = fieldIncDec(event, field, fieldMax, true)
end
end
end
local function getFieldFlags(position)
flags = 0
if field == position then
flags = INVERS
if edit then
flags = INVERS + BLINK
end
end
return flags
end
local function channelIncDec(event, value)
if not edit and event==EVT_MENU_BREAK then
servoPage = value
dirty = true
else
value = valueIncDec(event, value, 0, 15)
end
return value
end
-- Init function
local function init()
rudCH1 = defaultChannel(0)
thrCH1 = defaultChannel(2)
elevCH1 = defaultChannel(1)
elevCH2 = defaultChannel(3)
end
-- Engine Menu
local engineModeItems = {"No", "Yes..."}
local function drawEngineMenu()
lcd.clear()
lcd.drawText(1, 0, "Has your model got an engine?", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, engineModeItems, engineMode, getFieldFlags(0))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
if engineMode == 0 then
-- No engine
lcd.drawPixmap(132, 8, "engine-0.bmp")
fieldsMax = 0
else
-- 1 channel
lcd.drawPixmap(132, 8, "engine-1.bmp")
lcd.drawText(25, LCD_H-16, "Assign channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(151, LCD_H-8, MIXSRC_CH1+thrCH1, getFieldFlags(1))
fieldsMax = 1
end
end
local function engineMenu(event)
if dirty then
dirty = false
drawEngineMenu()
end
navigate(event, fieldsMax, page, page+1)
if field==0 then
engineMode = fieldIncDec(event, engineMode, 1)
elseif field==1 then
thrCH1 = channelIncDec(event, thrCH1)
end
end
-- Elevons Menu
local elevonsModeItems = {"2 Channels..."}
local function drawElevonsMenu()
lcd.clear()
lcd.drawText(1, 0, "Select elevon channnels", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, elevonsModeItems, elevonsMode, 0)
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(110, 9, "elevons.bmp")
lcd.drawText(20, LCD_H-16, "Assign channels", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(116, LCD_H-8, MIXSRC_CH1+elevCH1, getFieldFlags(0))
lcd.drawSource(175, LCD_H-8, MIXSRC_CH1+elevCH2, getFieldFlags(1))
fieldsMax = 1
end
local function elevonsMenu(event)
if dirty then
dirty = false
drawElevonsMenu()
end
navigate(event, fieldsMax, page-1, page+1)
if field==0 then
elevCH1 = channelIncDec(event, elevCH1)
elseif field==1 then
elevCH2 = channelIncDec(event, elevCH2)
end
end
-- Rudder menu
local rudderModeItems = {"No", "Yes..."}
local function drawRudderMenu()
lcd.clear()
lcd.drawText(1, 0, "Has your model got a rudder?", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, rudderModeItems, rudderMode, getFieldFlags(0))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
if rudderMode == 0 then
-- No rudder
lcd.drawPixmap(109, 14, "drudder-0.bmp")
fieldsMax = 0
else
-- 1 channel
lcd.drawPixmap(109, 14, "drudder-1.bmp")
lcd.drawText(25, LCD_H-16, "Assign channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(190, LCD_H-55, MIXSRC_CH1+rudCH1, getFieldFlags(1))
fieldsMax = 1
end
end
local function rudderMenu(event)
if dirty then
dirty = false
drawRudderMenu()
end
navigate(event, fieldsMax, page-1, page+1)
if field==0 then
rudderMode = fieldIncDec(event, rudderMode, 1)
elseif field==1 then
rudCH1 = channelIncDec(event, rudCH1)
end
end
-- Servo (limits) Menu
local function drawServoMenu(limits)
lcd.clear()
lcd.drawSource(1, 0, MIXSRC_CH1+servoPage, 0)
lcd.drawText(25, 0, "servo min/max/center/direction?", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawLine(LCD_W/2-1, 8, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawPixmap(122, 8, "servo.bmp")
lcd.drawNumber(140, 35, limits.min, PREC1+getFieldFlags(0));
lcd.drawNumber(205, 35, limits.max, PREC1+getFieldFlags(1));
lcd.drawNumber(170, 9, limits.offset, PREC1+getFieldFlags(2));
if limits.revert == 0 then
lcd.drawText(129, 50, "\126", getFieldFlags(3));
else
lcd.drawText(129, 50, "\127", getFieldFlags(3));
end
fieldsMax = 3
end
local function servoMenu(event)
local limits = model.getOutput(servoPage)
if dirty then
dirty = false
drawServoMenu(limits)
end
navigate(event, fieldsMax, page, page)
if edit then
if field==0 then
limits.min = valueIncDec(event, limits.min, -1000, 0)
elseif field==1 then
limits.max = valueIncDec(event, limits.max, 0, 1000)
elseif field==2 then
limits.offset = valueIncDec(event, limits.offset, -1000, 1000)
elseif field==3 then
limits.revert = fieldIncDec(event, limits.revert, 1)
end
model.setOutput(servoPage, limits)
elseif event == EVT_EXIT_BREAK then
servoPage = nil
dirty = true
end
end
-- Confirmation Menu
local function addMix(channel, input, name, weight, index)
local mix = { source=input, name=name }
if weight ~= nil then
mix.weight = weight
end
if index == nil then
index = 0
end
model.insertMix(channel, index, mix)
end
local function applySettings()
model.defaultInputs()
model.deleteMixes()
if engineMode == 1 then
addMix(thrCH1, MIXSRC_FIRST_INPUT+defaultChannel(2), "Engine")
end
addMix(elevCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "Elev1-E", 50)
addMix(elevCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "Elev1-A", 50, 1)
addMix(elevCH2, MIXSRC_FIRST_INPUT+defaultChannel(1), "Elev2-E", 50)
addMix(elevCH2, MIXSRC_FIRST_INPUT+defaultChannel(3), "Elev2-A", -50, 1)
if rudderMode == 1 then
addMix(rudCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "Rudder")
end
end
local function drawNextLine(x, y, label, channel)
lcd.drawText(x, y, label, 0);
lcd.drawSource(x+52, y, MIXSRC_CH1+channel, 0)
y = y + 8
if y > 50 then
y = 12
x = 120
end
return x, y
end
local function drawConfirmationMenu()
local x = 22
local y = 12
lcd.clear()
lcd.drawText(48, 1, "Ready to go?", 0);
lcd.drawFilledRectangle(0, 0, LCD_W, 9, 0)
if engineMode == 1 then
x, y = drawNextLine(x, y, "Throttle:", thrCH1)
end
x, y = drawNextLine(x, y, "Elevons:", elevCH1)
x, y = drawNextLine(x, y, "Elevons:", elevCH2)
if rudderMode == 1 then
drawNextLine(x, y, "Rudder:", rudCH1)
end
lcd.drawText(48, LCD_H-8, "[Enter Long] to confirm", 0);
lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0)
lcd.drawPixmap(LCD_W-18, 0, "confirm-tick.bmp")
lcd.drawPixmap(0, LCD_H-17, "confirm-plane.bmp")
fieldsMax = 0
end
local function confirmationMenu(event)
if dirty then
dirty = false
drawConfirmationMenu()
end
navigate(event, fieldsMax, RUDDER_PAGE, page)
if event == EVT_EXIT_BREAK then
return 2
elseif event == EVT_ENTER_LONG then
killEvents(event)
applySettings()
return 2
else
return 0
end
end
-- Main
local function run(event)
if event == nil then
error("Cannot be run as a model script!")
end
if servoPage ~= nil then
servoMenu(event)
elseif page == ENGINE_PAGE then
engineMenu(event)
elseif page == ELEVONS_PAGE then
elevonsMenu(event)
elseif page == RUDDER_PAGE then
rudderMenu(event)
elseif page == CONFIRMATION_PAGE then
return confirmationMenu(event)
end
return 0
end
return { init=init, run=run }

View file

@ -1,305 +1,305 @@
-- Multicopter Wizard pages
local THROTTLE_PAGE = 0
local ROLL_PAGE = 1
local PITCH_PAGE = 2
local YAW_PAGE = 3
local CONFIRMATION_PAGE = 4
-- Navigation variables
local page = THROTTLE_PAGE
local dirty = true
local edit = false
local field = 0
local fieldsMax = 0
local comboBoxMode = 0 -- Scrap variable
-- Model settings
local thrCH1 = 0
local rollCH1 = 0
local yawCH1 = 0
local pitchCH1 = 0
-- Common functions
local lastBlink = 0
local function blinkChanged()
local time = getTime() % 128
local blink = (time - time % 64) / 64
if blink ~= lastBlink then
lastBlink = blink
return true
else
return false
end
end
local function fieldIncDec(event, value, max, force)
if edit or force==true then
if event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT then
value = (value + max)
dirty = true
elseif event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT then
value = (value + max + 2)
dirty = true
end
value = (value % (max+1))
end
return value
end
local function valueIncDec(event, value, min, max)
if edit then
if event == EVT_PLUS_FIRST or event == EVT_PLUS_REPT or event == EVT_ROT_RIGHT then
if value < max then
value = (value + 1)
dirty = true
end
elseif event == EVT_MINUS_FIRST or event == EVT_MINUS_REPT or event == EVT_ROT_LEFT then
if value > min then
value = (value - 1)
dirty = true
end
end
end
return value
end
local function navigate(event, fieldMax, prevPage, nextPage)
if event == EVT_ENTER_BREAK then
edit = not edit
dirty = true
elseif edit then
if event == EVT_EXIT_BREAK then
edit = false
dirty = true
elseif not dirty then
dirty = blinkChanged()
end
else
if event == EVT_PAGE_BREAK then
page = nextPage
field = 0
dirty = true
elseif event == EVT_PAGE_LONG then
page = prevPage
field = 0
killEvents(event);
dirty = true
else
field = fieldIncDec(event, field, fieldMax, true)
end
end
end
local function getFieldFlags(position)
flags = 0
if field == position then
flags = INVERS
if edit then
flags = INVERS + BLINK
end
end
return flags
end
local function channelIncDec(event, value)
if not edit and event==EVT_MENU_BREAK then
servoPage = value
dirty = true
else
value = valueIncDec(event, value, 0, 15)
end
return value
end
-- Init function
local function init()
thrCH1 = defaultChannel(2)
rollCH1 = defaultChannel(3)
yawCH1 = defaultChannel(0)
pitchCH1 = defaultChannel(1)
end
-- Throttle Menu
local function drawThrottleMenu()
lcd.clear()
lcd.drawText(1, 0, "Select multicopter throttle channel", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(120, 8, "multi-thr.bmp")
lcd.drawText(20, LCD_H-16, "Assign Throttle", 0);
lcd.drawText(20, LCD_H-8, "Channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+thrCH1, getFieldFlags(0))
fieldsMax = 0
end
local function throttleMenu(event)
if dirty then
dirty = false
drawThrottleMenu()
end
navigate(event, fieldsMax, page, page+1)
thrCH1 = channelIncDec(event, thrCH1)
end
-- Roll Menu
local function drawRollMenu()
lcd.clear()
lcd.drawText(1, 0, "Select multicopter roll channel", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(120, 8, "multi-roll.bmp")
lcd.drawText(20, LCD_H-16, "Assign Roll", 0);
lcd.drawText(20, LCD_H-8, "Channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+rollCH1, getFieldFlags(0))
fieldsMax = 0
end
local function rollMenu(event)
if dirty then
dirty = false
drawRollMenu()
end
navigate(event, fieldsMax, page-1, page+1)
rollCH1 = channelIncDec(event, rollCH1)
end
-- Pitch Menu
local function drawPitchMenu()
lcd.clear()
lcd.drawText(1, 0, "Select multicopter pitch channel", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(120, 8, "multi-pitch.bmp")
lcd.drawText(20, LCD_H-16, "Assign Pitch", 0);
lcd.drawText(20, LCD_H-8, "Channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+pitchCH1, getFieldFlags(0))
fieldsMax = 0
end
local function pitchMenu(event)
if dirty then
dirty = false
drawPitchMenu()
end
navigate(event, fieldsMax, page-1, page+1)
pitchCH1 = channelIncDec(event, pitchCH1)
end
-- Yaw Menu
local function drawYawMenu()
lcd.clear()
lcd.drawText(1, 0, "Select multicopter yaw channel", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(120, 8, "multi-yaw.bmp")
lcd.drawText(20, LCD_H-16, "Assign Yaw", 0);
lcd.drawText(20, LCD_H-8, "Channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+yawCH1, getFieldFlags(0))
fieldsMax = 0
end
local function yawMenu(event)
if dirty then
dirty = false
drawYawMenu()
end
navigate(event, fieldsMax, page-1, page+1)
yawCH1 = channelIncDec(event, yawCH1)
end
-- Confirmation Menu
local function drawNextLine(x, y, label, channel)
lcd.drawText(x, y, label, 0);
lcd.drawSource(x+52, y, MIXSRC_CH1+channel, 0)
y = y + 8
if y > 50 then
y = 12
x = 120
end
return x, y
end
local function drawConfirmationMenu()
local x = 22
local y = 12
lcd.clear()
lcd.drawText(48, 1, "Ready to go?", 0);
lcd.drawFilledRectangle(0, 0, LCD_W, 9, 0)
x, y = drawNextLine(x, y, "Throttle:", thrCH1)
x, y = drawNextLine(x, y, "Roll:", rollCH1)
x, y = drawNextLine(x, y, "Pitch:", pitchCH1)
x, y = drawNextLine(x, y, "Yaw:", yawCH1)
lcd.drawText(48, LCD_H-8, "[Enter Long] to confirm", 0);
lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0)
lcd.drawPixmap(LCD_W-18, 0, "confirm-tick.bmp")
lcd.drawPixmap(0, LCD_H-17, "confirm-plane.bmp")
fieldsMax = 0
end
local function addMix(channel, input, name, weight, index)
local mix = { source=input, name=name }
if weight ~= nil then
mix.weight = weight
end
if index == nil then
index = 0
end
model.insertMix(channel, index, mix)
end
local function applySettings()
model.defaultInputs()
model.deleteMixes()
addMix(thrCH1, MIXSRC_FIRST_INPUT+defaultChannel(2), "Throttle")
addMix(rollCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "Roll")
addMix(yawCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "Yaw")
addMix(pitchCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "Pitch")
end
local function confirmationMenu(event)
if dirty then
dirty = false
drawConfirmationMenu()
end
navigate(event, fieldsMax, YAW_PAGE, page)
if event == EVT_EXIT_BREAK then
return 2
elseif event == EVT_ENTER_LONG then
killEvents(event)
applySettings()
return 2
else
return 0
end
end
-- Main
local function run(event)
if event == nil then
error("Cannot be run as a model script!")
end
if page == THROTTLE_PAGE then
throttleMenu(event)
elseif page == ROLL_PAGE then
rollMenu(event)
elseif page == YAW_PAGE then
yawMenu(event)
elseif page == PITCH_PAGE then
pitchMenu(event)
elseif page == CONFIRMATION_PAGE then
return confirmationMenu(event)
end
return 0
end
return { init=init, run=run }
-- Multicopter Wizard pages
local THROTTLE_PAGE = 0
local ROLL_PAGE = 1
local PITCH_PAGE = 2
local YAW_PAGE = 3
local CONFIRMATION_PAGE = 4
-- Navigation variables
local page = THROTTLE_PAGE
local dirty = true
local edit = false
local field = 0
local fieldsMax = 0
local comboBoxMode = 0 -- Scrap variable
-- Model settings
local thrCH1 = 0
local rollCH1 = 0
local yawCH1 = 0
local pitchCH1 = 0
-- Common functions
local lastBlink = 0
local function blinkChanged()
local time = getTime() % 128
local blink = (time - time % 64) / 64
if blink ~= lastBlink then
lastBlink = blink
return true
else
return false
end
end
local function fieldIncDec(event, value, max, force)
if edit or force==true then
if event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT then
value = (value + max)
dirty = true
elseif event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT then
value = (value + max + 2)
dirty = true
end
value = (value % (max+1))
end
return value
end
local function valueIncDec(event, value, min, max)
if edit then
if event == EVT_PLUS_FIRST or event == EVT_PLUS_REPT or event == EVT_ROT_RIGHT then
if value < max then
value = (value + 1)
dirty = true
end
elseif event == EVT_MINUS_FIRST or event == EVT_MINUS_REPT or event == EVT_ROT_LEFT then
if value > min then
value = (value - 1)
dirty = true
end
end
end
return value
end
local function navigate(event, fieldMax, prevPage, nextPage)
if event == EVT_ENTER_BREAK then
edit = not edit
dirty = true
elseif edit then
if event == EVT_EXIT_BREAK then
edit = false
dirty = true
elseif not dirty then
dirty = blinkChanged()
end
else
if event == EVT_PAGE_BREAK then
page = nextPage
field = 0
dirty = true
elseif event == EVT_PAGE_LONG then
page = prevPage
field = 0
killEvents(event);
dirty = true
else
field = fieldIncDec(event, field, fieldMax, true)
end
end
end
local function getFieldFlags(position)
flags = 0
if field == position then
flags = INVERS
if edit then
flags = INVERS + BLINK
end
end
return flags
end
local function channelIncDec(event, value)
if not edit and event==EVT_MENU_BREAK then
servoPage = value
dirty = true
else
value = valueIncDec(event, value, 0, 15)
end
return value
end
-- Init function
local function init()
thrCH1 = defaultChannel(2)
rollCH1 = defaultChannel(3)
yawCH1 = defaultChannel(0)
pitchCH1 = defaultChannel(1)
end
-- Throttle Menu
local function drawThrottleMenu()
lcd.clear()
lcd.drawText(1, 0, "Select multicopter throttle channel", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(120, 8, "multi-thr.bmp")
lcd.drawText(20, LCD_H-16, "Assign Throttle", 0);
lcd.drawText(20, LCD_H-8, "Channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+thrCH1, getFieldFlags(0))
fieldsMax = 0
end
local function throttleMenu(event)
if dirty then
dirty = false
drawThrottleMenu()
end
navigate(event, fieldsMax, page, page+1)
thrCH1 = channelIncDec(event, thrCH1)
end
-- Roll Menu
local function drawRollMenu()
lcd.clear()
lcd.drawText(1, 0, "Select multicopter roll channel", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(120, 8, "multi-roll.bmp")
lcd.drawText(20, LCD_H-16, "Assign Roll", 0);
lcd.drawText(20, LCD_H-8, "Channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+rollCH1, getFieldFlags(0))
fieldsMax = 0
end
local function rollMenu(event)
if dirty then
dirty = false
drawRollMenu()
end
navigate(event, fieldsMax, page-1, page+1)
rollCH1 = channelIncDec(event, rollCH1)
end
-- Pitch Menu
local function drawPitchMenu()
lcd.clear()
lcd.drawText(1, 0, "Select multicopter pitch channel", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(120, 8, "multi-pitch.bmp")
lcd.drawText(20, LCD_H-16, "Assign Pitch", 0);
lcd.drawText(20, LCD_H-8, "Channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+pitchCH1, getFieldFlags(0))
fieldsMax = 0
end
local function pitchMenu(event)
if dirty then
dirty = false
drawPitchMenu()
end
navigate(event, fieldsMax, page-1, page+1)
pitchCH1 = channelIncDec(event, pitchCH1)
end
-- Yaw Menu
local function drawYawMenu()
lcd.clear()
lcd.drawText(1, 0, "Select multicopter yaw channel", 0)
lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1))
lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
lcd.drawPixmap(120, 8, "multi-yaw.bmp")
lcd.drawText(20, LCD_H-16, "Assign Yaw", 0);
lcd.drawText(20, LCD_H-8, "Channel", 0);
lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+yawCH1, getFieldFlags(0))
fieldsMax = 0
end
local function yawMenu(event)
if dirty then
dirty = false
drawYawMenu()
end
navigate(event, fieldsMax, page-1, page+1)
yawCH1 = channelIncDec(event, yawCH1)
end
-- Confirmation Menu
local function drawNextLine(x, y, label, channel)
lcd.drawText(x, y, label, 0);
lcd.drawSource(x+52, y, MIXSRC_CH1+channel, 0)
y = y + 8
if y > 50 then
y = 12
x = 120
end
return x, y
end
local function drawConfirmationMenu()
local x = 22
local y = 12
lcd.clear()
lcd.drawText(48, 1, "Ready to go?", 0);
lcd.drawFilledRectangle(0, 0, LCD_W, 9, 0)
x, y = drawNextLine(x, y, "Throttle:", thrCH1)
x, y = drawNextLine(x, y, "Roll:", rollCH1)
x, y = drawNextLine(x, y, "Pitch:", pitchCH1)
x, y = drawNextLine(x, y, "Yaw:", yawCH1)
lcd.drawText(48, LCD_H-8, "[Enter Long] to confirm", 0);
lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0)
lcd.drawPixmap(LCD_W-18, 0, "confirm-tick.bmp")
lcd.drawPixmap(0, LCD_H-17, "confirm-plane.bmp")
fieldsMax = 0
end
local function addMix(channel, input, name, weight, index)
local mix = { source=input, name=name }
if weight ~= nil then
mix.weight = weight
end
if index == nil then
index = 0
end
model.insertMix(channel, index, mix)
end
local function applySettings()
model.defaultInputs()
model.deleteMixes()
addMix(thrCH1, MIXSRC_FIRST_INPUT+defaultChannel(2), "Throttle")
addMix(rollCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "Roll")
addMix(yawCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "Yaw")
addMix(pitchCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "Pitch")
end
local function confirmationMenu(event)
if dirty then
dirty = false
drawConfirmationMenu()
end
navigate(event, fieldsMax, YAW_PAGE, page)
if event == EVT_EXIT_BREAK then
return 2
elseif event == EVT_ENTER_LONG then
killEvents(event)
applySettings()
return 2
else
return 0
end
end
-- Main
local function run(event)
if event == nil then
error("Cannot be run as a model script!")
end
if page == THROTTLE_PAGE then
throttleMenu(event)
elseif page == ROLL_PAGE then
rollMenu(event)
elseif page == YAW_PAGE then
yawMenu(event)
elseif page == PITCH_PAGE then
pitchMenu(event)
elseif page == CONFIRMATION_PAGE then
return confirmationMenu(event)
end
return 0
end
return { init=init, run=run }

File diff suppressed because it is too large Load diff

View file

@ -1,74 +1,74 @@
-- Navigation variables
local dirty = true
-- Model types
local modelType = 0
local MODELTYPE_PLANE = 0
--local MODELTYPE_HELI = 1
local MODELTYPE_DELTA = 1
local MODELTYPE_QUAD = 2
-- Common functions
local function fieldIncDec(event, value, max)
if event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT or event == EVT_PLUS_REPT then
value = (value + max)
dirty = true
elseif event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT or event == EVT_MINUS_REPT then
value = (value + max + 2)
dirty = true
end
value = (value % (max+1))
return value
end
-- Model Type Menu
local function modelTypeSurround(index)
lcd.drawRectangle(12+47*index, 13, 48, 48)
lcd.drawPixmap(17+47*index, 8, "mark.bmp")
end
local function drawModelChoiceMenu()
lcd.clear()
lcd.drawScreenTitle("", 0, 0)
-- lcd.drawText(58, 13, "Select model type", 0)
lcd.drawPixmap( 16, 17, "plane.bmp")
--lcd.drawPixmap( 63, 17, "heli.bmp")
lcd.drawPixmap(63, 17, "delta.bmp")
lcd.drawPixmap(110, 17, "quadri.bmp")
modelTypeSurround(modelType)
end
local function modelTypeMenu(event)
if dirty == true then
drawModelChoiceMenu()
dirty = false
end
if event == EVT_ENTER_BREAK then
if modelType == MODELTYPE_PLANE then
return "plane.lua"
elseif modelType == MODELTYPE_HELI then
elseif modelType == MODELTYPE_DELTA then
return "delta.lua"
elseif modelType == MODELTYPE_QUAD then
return "multi.lua"
end
dirty = true
else
modelType = fieldIncDec(event, modelType, 2)
end
return 0
end
-- Main
local function run(event)
if event == nil then
error("Cannot be run as a model script!")
end
if event == EVT_EXIT_BREAK then
return 2
end
return modelTypeMenu(event)
end
return { run=run }
-- Navigation variables
local dirty = true
-- Model types
local modelType = 0
local MODELTYPE_PLANE = 0
--local MODELTYPE_HELI = 1
local MODELTYPE_DELTA = 1
local MODELTYPE_QUAD = 2
-- Common functions
local function fieldIncDec(event, value, max)
if event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT or event == EVT_PLUS_REPT then
value = (value + max)
dirty = true
elseif event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT or event == EVT_MINUS_REPT then
value = (value + max + 2)
dirty = true
end
value = (value % (max+1))
return value
end
-- Model Type Menu
local function modelTypeSurround(index)
lcd.drawRectangle(12+47*index, 13, 48, 48)
lcd.drawPixmap(17+47*index, 8, "mark.bmp")
end
local function drawModelChoiceMenu()
lcd.clear()
lcd.drawScreenTitle("", 0, 0)
-- lcd.drawText(58, 13, "Select model type", 0)
lcd.drawPixmap( 16, 17, "plane.bmp")
--lcd.drawPixmap( 63, 17, "heli.bmp")
lcd.drawPixmap(63, 17, "delta.bmp")
lcd.drawPixmap(110, 17, "quadri.bmp")
modelTypeSurround(modelType)
end
local function modelTypeMenu(event)
if dirty == true then
drawModelChoiceMenu()
dirty = false
end
if event == EVT_ENTER_BREAK then
if modelType == MODELTYPE_PLANE then
return "plane.lua"
elseif modelType == MODELTYPE_HELI then
elseif modelType == MODELTYPE_DELTA then
return "delta.lua"
elseif modelType == MODELTYPE_QUAD then
return "multi.lua"
end
dirty = true
else
modelType = fieldIncDec(event, modelType, 2)
end
return 0
end
-- Main
local function run(event)
if event == nil then
error("Cannot be run as a model script!")
end
if event == EVT_EXIT_BREAK then
return 2
end
return modelTypeMenu(event)
end
return { run=run }

View file

@ -1,176 +1,176 @@
--------------------------------------------------------------
-- Classic snake game
--
-- 2009 Led Lab @PUC-Rio www.eluaproject.net
-- Dado Sutter
-- Ives Negreiros
-- To Benjamin
---------------------------------------------------------------
local xMax = math.floor( LCD_W / 6 ) - 1
local yMax = math.floor( LCD_H / 8 ) - 1
local game_map = {}
local Head = {}
local Tail = {}
local highscore = 0
local size = 3
Tail.x = 1
Tail.y = 1
Head.x = Tail.x + ( size - 1 )
Head.y = Tail.y
local Food = {}
Food.x = false
Food.y = false
Head.dx = 1
Head.dy = 0
Tail.dx = Head.dx
Tail.dy = Head.dy
local direction = "right"
local score = 0
local function create_food()
Food.x, Food.y = math.random( xMax - 1), math.random( yMax - 1)
while game_map[ Food.x ][ Food.y ] do
Food.x, Food.y = math.random( xMax - 1 ), math.random( yMax - 1 )
end
game_map[ Food.x ][ Food.y ] = "food"
lcd.drawText( Food.x * 6, Food.y * 8+2, "@", 0 )
end
local function eat_food()
playFile("/SCRIPTS/snake.wav")
lcd.drawText( Head.x * 6, Head.y * 8, " ", 0 )
game_map[ Head.x ][ Head.y ] = nil
create_food()
score = score + 1
end
local function check_collision()
if Head.x < 0 or Head.x > xMax then
return true
elseif Head.y < 0 or Head.y > yMax then
return true
elseif ( ( game_map[ Head.x ][ Head.y ] ) and ( game_map[ Head.x ][ Head.y ] ~= "food" ) ) then
return true
end
return false
end
local function move()
if game_map[ Tail.x ][ Tail.y ] == "right" then
Tail.dx = 1
Tail.dy = 0
elseif game_map[ Tail.x ][ Tail.y ] == "left" then
Tail.dx = -1
Tail.dy = 0
elseif game_map[ Tail.x ][ Tail.y ] == "up" then
Tail.dx = 0
Tail.dy = -1
elseif game_map[ Tail.x ][ Tail.y ] == "down" then
Tail.dx = 0
Tail.dy = 1
end
game_map[ Head.x ][ Head.y ] = direction
Head.x = Head.x + Head.dx
Head.y = Head.y + Head.dy
if Head.x < 0 or Head.x > xMax or Head.y < 0 or Head.y > yMax then
return
elseif game_map[ Head.x ][ Head.y ] == "food" then
eat_food()
else
lcd.drawText(Tail.x * 6, Tail.y * 8, " ", 16)
game_map[ Tail.x ][ Tail.y ] = nil
Tail.x = Tail.x + Tail.dx
Tail.y = Tail.y + Tail.dy
end
lcd.drawText(Head.x * 6, Head.y * 8, "*", 0)
end
local function init()
food = false
lcd.clear()
size = 3
score = 0
Tail.x = 1
Tail.y = 1
Head.x = Tail.x + ( size - 1 )
Head.y = Tail.y
Head.dx = 1
Head.dy = 0
Tail.dx = Head.dx
Tail.dy = Head.dy
direction = "right"
for i = 0, xMax, 1 do
game_map[ i ] = {}
end
for i = 0, size - 1, 1 do
game_map[ Tail.x + ( i * Tail.dx ) ][ Tail.y + ( i * Tail.dy ) ] = direction
lcd.drawText( ( Tail.x + ( i * Tail.dx ) ) * 6, ( Tail.y + ( i * Tail.dy ) ) * 8, "*", 0 )
end
create_food()
end
local snakeCounter = 0
local function run(event)
if event == nil then
raise("Cannot be run as a model script!")
end
if event == EVT_EXIT_BREAK then
return 2
end
snakeCounter = snakeCounter + 1
if snakeCounter < 30 then
return 0
end
snakeCounter = 0
local dir = direction
if getValue('rud') > 100 and direction ~= "left" then
dir = "right"
Head.dx = 1
Head.dy = 0
end
if getValue('rud') < -100 and direction ~= "right" then
dir = "left"
Head.dx = -1
Head.dy = 0
end
if getValue('ele') > 100 and direction ~= "down" then
dir = "up"
Head.dx = 0
Head.dy = -1
end
if getValue('ele') < -100 and direction ~= "up" then
dir = "down"
Head.dx = 0
Head.dy = 1
end
direction = dir
move()
lcd.refresh()
if check_collision() then
return 1
end
return 0
end
return { init=init, run=run }
--------------------------------------------------------------
-- Classic snake game
--
-- 2009 Led Lab @PUC-Rio www.eluaproject.net
-- Dado Sutter
-- Ives Negreiros
-- To Benjamin
---------------------------------------------------------------
local xMax = math.floor( LCD_W / 6 ) - 1
local yMax = math.floor( LCD_H / 8 ) - 1
local game_map = {}
local Head = {}
local Tail = {}
local highscore = 0
local size = 3
Tail.x = 1
Tail.y = 1
Head.x = Tail.x + ( size - 1 )
Head.y = Tail.y
local Food = {}
Food.x = false
Food.y = false
Head.dx = 1
Head.dy = 0
Tail.dx = Head.dx
Tail.dy = Head.dy
local direction = "right"
local score = 0
local function create_food()
Food.x, Food.y = math.random( xMax - 1), math.random( yMax - 1)
while game_map[ Food.x ][ Food.y ] do
Food.x, Food.y = math.random( xMax - 1 ), math.random( yMax - 1 )
end
game_map[ Food.x ][ Food.y ] = "food"
lcd.drawText( Food.x * 6, Food.y * 8+2, "@", 0 )
end
local function eat_food()
playFile("/SCRIPTS/snake.wav")
lcd.drawText( Head.x * 6, Head.y * 8, " ", 0 )
game_map[ Head.x ][ Head.y ] = nil
create_food()
score = score + 1
end
local function check_collision()
if Head.x < 0 or Head.x > xMax then
return true
elseif Head.y < 0 or Head.y > yMax then
return true
elseif ( ( game_map[ Head.x ][ Head.y ] ) and ( game_map[ Head.x ][ Head.y ] ~= "food" ) ) then
return true
end
return false
end
local function move()
if game_map[ Tail.x ][ Tail.y ] == "right" then
Tail.dx = 1
Tail.dy = 0
elseif game_map[ Tail.x ][ Tail.y ] == "left" then
Tail.dx = -1
Tail.dy = 0
elseif game_map[ Tail.x ][ Tail.y ] == "up" then
Tail.dx = 0
Tail.dy = -1
elseif game_map[ Tail.x ][ Tail.y ] == "down" then
Tail.dx = 0
Tail.dy = 1
end
game_map[ Head.x ][ Head.y ] = direction
Head.x = Head.x + Head.dx
Head.y = Head.y + Head.dy
if Head.x < 0 or Head.x > xMax or Head.y < 0 or Head.y > yMax then
return
elseif game_map[ Head.x ][ Head.y ] == "food" then
eat_food()
else
lcd.drawText(Tail.x * 6, Tail.y * 8, " ", 16)
game_map[ Tail.x ][ Tail.y ] = nil
Tail.x = Tail.x + Tail.dx
Tail.y = Tail.y + Tail.dy
end
lcd.drawText(Head.x * 6, Head.y * 8, "*", 0)
end
local function init()
food = false
lcd.clear()
size = 3
score = 0
Tail.x = 1
Tail.y = 1
Head.x = Tail.x + ( size - 1 )
Head.y = Tail.y
Head.dx = 1
Head.dy = 0
Tail.dx = Head.dx
Tail.dy = Head.dy
direction = "right"
for i = 0, xMax, 1 do
game_map[ i ] = {}
end
for i = 0, size - 1, 1 do
game_map[ Tail.x + ( i * Tail.dx ) ][ Tail.y + ( i * Tail.dy ) ] = direction
lcd.drawText( ( Tail.x + ( i * Tail.dx ) ) * 6, ( Tail.y + ( i * Tail.dy ) ) * 8, "*", 0 )
end
create_food()
end
local snakeCounter = 0
local function run(event)
if event == nil then
raise("Cannot be run as a model script!")
end
if event == EVT_EXIT_BREAK then
return 2
end
snakeCounter = snakeCounter + 1
if snakeCounter < 30 then
return 0
end
snakeCounter = 0
local dir = direction
if getValue('rud') > 100 and direction ~= "left" then
dir = "right"
Head.dx = 1
Head.dy = 0
end
if getValue('rud') < -100 and direction ~= "right" then
dir = "left"
Head.dx = -1
Head.dy = 0
end
if getValue('ele') > 100 and direction ~= "down" then
dir = "up"
Head.dx = 0
Head.dy = -1
end
if getValue('ele') < -100 and direction ~= "up" then
dir = "down"
Head.dx = 0
Head.dy = 1
end
direction = dir
move()
lcd.refresh()
if check_collision() then
return 1
end
return 0
end
return { init=init, run=run }

View file

@ -1,11 +1,11 @@
#define sticks_4x1_width 18
#define sticks_4x1_height 32
static unsigned char sticks_4x1_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x88, 0x00, 0x44, 0x00, 0x00,
0xfe, 0x24, 0x01, 0x44, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x00, 0x20, 0x20, 0x00, 0x70, 0x88, 0x00, 0x20, 0x00, 0x00,
0x20, 0x24, 0x01, 0x20, 0x00, 0x00, 0x70, 0x88, 0x00, 0x20, 0x20, 0x00,
0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x44, 0x38, 0x00, 0x00, 0x10, 0x00,
0x92, 0x10, 0x00, 0x00, 0x10, 0x00, 0x44, 0x38, 0x00, 0x10, 0x10, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x88, 0x00,
0x92, 0xfc, 0x01, 0x00, 0x88, 0x00, 0x44, 0x00, 0x00, 0x10, 0x00, 0x00 };
#define sticks_4x1_width 18
#define sticks_4x1_height 32
static unsigned char sticks_4x1_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x88, 0x00, 0x44, 0x00, 0x00,
0xfe, 0x24, 0x01, 0x44, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x00, 0x20, 0x20, 0x00, 0x70, 0x88, 0x00, 0x20, 0x00, 0x00,
0x20, 0x24, 0x01, 0x20, 0x00, 0x00, 0x70, 0x88, 0x00, 0x20, 0x20, 0x00,
0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x44, 0x38, 0x00, 0x00, 0x10, 0x00,
0x92, 0x10, 0x00, 0x00, 0x10, 0x00, 0x44, 0x38, 0x00, 0x10, 0x10, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x88, 0x00,
0x92, 0xfc, 0x01, 0x00, 0x88, 0x00, 0x44, 0x00, 0x00, 0x10, 0x00, 0x00 };

View file

@ -1,175 +1,175 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BUZZER_H_
#define _BUZZER_H_
#if defined(BUZZER)
extern uint8_t g_beepCnt;
extern uint8_t beepAgain;
extern uint8_t beepAgainOrig;
extern uint8_t beepOn;
extern bool warble;
extern bool warbleC;
#if defined(HAPTIC)
extern uint8_t hapticTick;
#endif /* HAPTIC */
#endif /* BUZZER */
#if defined(BUZZER)
#if defined(CPUARM) && !defined(SIMU)
inline void _beep(uint8_t b)
{
buzzerSound(b);
}
#else /* CPUARM && !SIMU */
inline void _beep(uint8_t b)
{
g_beepCnt = b;
}
#endif /* CPUARM && !SIMU */
void beep(uint8_t val);
#else /* BUZZER */
inline void beep(uint8_t) { }
#endif /* BUZZER */
#if !defined(AUDIO)
#if defined(BUZZER)
#if defined(VOICE)
#define AUDIO_HELLO() PUSH_SYSTEM_PROMPT(AUDIO_HELLO)
#define AUDIO_BYE()
#define AUDIO_TX_BATTERY_LOW() PUSH_SYSTEM_PROMPT(AU_TX_BATTERY_LOW)
#define AUDIO_INACTIVITY() PUSH_SYSTEM_PROMPT(AU_INACTIVITY)
#define AUDIO_ERROR_MESSAGE(e) PUSH_SYSTEM_PROMPT((e))
#define AUDIO_TIMER_MINUTE(t) playDuration(t)
// TODO
#define AUDIO_TIMER_30() PUSH_SYSTEM_PROMPT(AU_TIMER_30)
#define AUDIO_TIMER_20() PUSH_SYSTEM_PROMPT(AU_TIMER_20)
#else
#define AUDIO_HELLO()
#define AUDIO_BYE()
#define AUDIO_TX_BATTERY_LOW() beep(4)
#define AUDIO_INACTIVITY() beep(3)
#define AUDIO_ERROR_MESSAGE(e) beep(4)
#define AUDIO_TIMER_MINUTE(t) beep(2)
// TODO
#define AUDIO_TIMER_30() { beepAgain=2; beep(2); }
#define AUDIO_TIMER_20() { beepAgain=1; beep(2); }
#endif
#define AUDIO_KEY_PRESS() beep(0)
#define AUDIO_KEY_ERROR() beep(2)
#define AUDIO_WARNING2() beep(2)
#define AUDIO_WARNING1() beep(3)
#define AUDIO_ERROR() beep(4)
#define AUDIO_MIX_WARNING(x) beep(1)
#define AUDIO_POT_MIDDLE() beep(2)
#define AUDIO_TIMER_COUNTDOWN(idx, val) beep(2)
#define AUDIO_TIMER_ELAPSED(idx) beep(3)
#define AUDIO_VARIO_UP() _beep(1)
#define AUDIO_VARIO_DOWN() _beep(1)
#define AUDIO_TRIM_PRESS(f) { if (!IS_KEY_FIRST(event)) warble = true; beep(1); }
#define AUDIO_TRIM_MIDDLE() beep(2)
#define AUDIO_TRIM_MIN() beep(2)
#define AUDIO_TRIM_MAX() beep(2)
#define AUDIO_PLAY(p) beep(3)
#define IS_AUDIO_BUSY() (g_beepCnt || beepAgain || beepOn)
#else /* BUZZER */
#define AUDIO_HELLO()
#define AUDIO_BYE()
#define AUDIO_TX_BATTERY_LOW()
#define AUDIO_INACTIVITY()
#define AUDIO_ERROR_MESSAGE(e)
#define AUDIO_TIMER_MINUTE(t)
#define AUDIO_TIMER_30()
#define AUDIO_TIMER_20()
#define AUDIO_WARNING2()
#define AUDIO_WARNING1()
#define AUDIO_ERROR()
#define AUDIO_MIX_WARNING(x)
#define AUDIO_POT_MIDDLE()
#define AUDIO_TIMER_LT10(m, x)
#define AUDIO_TIMER_00(m)
#define AUDIO_VARIO_UP()
#define AUDIO_VARIO_DOWN()
#define AUDIO_TRIM(event, f)
#define AUDIO_TRIM_MIDDLE(f)
#define AUDIO_TRIM_END(f)
#define AUDIO_PLAY(p)
#define IS_AUDIO_BUSY() false
#endif /* BUZZER */
#define AUDIO_RESET()
#define AUDIO_FLUSH()
#define PLAY_PHASE_OFF(phase)
#define PLAY_PHASE_ON(phase)
#define PLAY_SWITCH_MOVED(sw)
#define PLAY_LOGICAL_SWITCH_OFF(sw)
#define PLAY_LOGICAL_SWITCH_ON(sw)
#define PLAY_MODEL_NAME()
#define START_SILENCE_PERIOD()
#endif /* !AUDIO */
#if !defined(CPUARM)
#if defined(BUZZER)
inline void BUZZER_HEARTBEAT()
{
if (g_beepCnt) {
if (!beepAgainOrig) {
beepAgainOrig = g_beepCnt;
beepOn = true;
}
g_beepCnt--;
}
else {
if (beepAgain && beepAgainOrig) {
beepOn = !beepOn;
g_beepCnt = beepOn ? beepAgainOrig : 8;
if (beepOn) beepAgain--;
}
else {
beepAgainOrig = 0;
beepOn = false;
warble = false;
}
}
if (beepOn) {
warbleC = warble && !warbleC;
if (warbleC)
buzzerOff();
else
buzzerOn();
}
else {
buzzerOff();
}
}
#else // BUZZER
#define BUZZER_HEARTBEAT()
#endif // BUZZER
#endif // CPUARM
#endif // _BUZZER_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BUZZER_H_
#define _BUZZER_H_
#if defined(BUZZER)
extern uint8_t g_beepCnt;
extern uint8_t beepAgain;
extern uint8_t beepAgainOrig;
extern uint8_t beepOn;
extern bool warble;
extern bool warbleC;
#if defined(HAPTIC)
extern uint8_t hapticTick;
#endif /* HAPTIC */
#endif /* BUZZER */
#if defined(BUZZER)
#if defined(CPUARM) && !defined(SIMU)
inline void _beep(uint8_t b)
{
buzzerSound(b);
}
#else /* CPUARM && !SIMU */
inline void _beep(uint8_t b)
{
g_beepCnt = b;
}
#endif /* CPUARM && !SIMU */
void beep(uint8_t val);
#else /* BUZZER */
inline void beep(uint8_t) { }
#endif /* BUZZER */
#if !defined(AUDIO)
#if defined(BUZZER)
#if defined(VOICE)
#define AUDIO_HELLO() PUSH_SYSTEM_PROMPT(AUDIO_HELLO)
#define AUDIO_BYE()
#define AUDIO_TX_BATTERY_LOW() PUSH_SYSTEM_PROMPT(AU_TX_BATTERY_LOW)
#define AUDIO_INACTIVITY() PUSH_SYSTEM_PROMPT(AU_INACTIVITY)
#define AUDIO_ERROR_MESSAGE(e) PUSH_SYSTEM_PROMPT((e))
#define AUDIO_TIMER_MINUTE(t) playDuration(t)
// TODO
#define AUDIO_TIMER_30() PUSH_SYSTEM_PROMPT(AU_TIMER_30)
#define AUDIO_TIMER_20() PUSH_SYSTEM_PROMPT(AU_TIMER_20)
#else
#define AUDIO_HELLO()
#define AUDIO_BYE()
#define AUDIO_TX_BATTERY_LOW() beep(4)
#define AUDIO_INACTIVITY() beep(3)
#define AUDIO_ERROR_MESSAGE(e) beep(4)
#define AUDIO_TIMER_MINUTE(t) beep(2)
// TODO
#define AUDIO_TIMER_30() { beepAgain=2; beep(2); }
#define AUDIO_TIMER_20() { beepAgain=1; beep(2); }
#endif
#define AUDIO_KEY_PRESS() beep(0)
#define AUDIO_KEY_ERROR() beep(2)
#define AUDIO_WARNING2() beep(2)
#define AUDIO_WARNING1() beep(3)
#define AUDIO_ERROR() beep(4)
#define AUDIO_MIX_WARNING(x) beep(1)
#define AUDIO_POT_MIDDLE() beep(2)
#define AUDIO_TIMER_COUNTDOWN(idx, val) beep(2)
#define AUDIO_TIMER_ELAPSED(idx) beep(3)
#define AUDIO_VARIO_UP() _beep(1)
#define AUDIO_VARIO_DOWN() _beep(1)
#define AUDIO_TRIM_PRESS(f) { if (!IS_KEY_FIRST(event)) warble = true; beep(1); }
#define AUDIO_TRIM_MIDDLE() beep(2)
#define AUDIO_TRIM_MIN() beep(2)
#define AUDIO_TRIM_MAX() beep(2)
#define AUDIO_PLAY(p) beep(3)
#define IS_AUDIO_BUSY() (g_beepCnt || beepAgain || beepOn)
#else /* BUZZER */
#define AUDIO_HELLO()
#define AUDIO_BYE()
#define AUDIO_TX_BATTERY_LOW()
#define AUDIO_INACTIVITY()
#define AUDIO_ERROR_MESSAGE(e)
#define AUDIO_TIMER_MINUTE(t)
#define AUDIO_TIMER_30()
#define AUDIO_TIMER_20()
#define AUDIO_WARNING2()
#define AUDIO_WARNING1()
#define AUDIO_ERROR()
#define AUDIO_MIX_WARNING(x)
#define AUDIO_POT_MIDDLE()
#define AUDIO_TIMER_LT10(m, x)
#define AUDIO_TIMER_00(m)
#define AUDIO_VARIO_UP()
#define AUDIO_VARIO_DOWN()
#define AUDIO_TRIM(event, f)
#define AUDIO_TRIM_MIDDLE(f)
#define AUDIO_TRIM_END(f)
#define AUDIO_PLAY(p)
#define IS_AUDIO_BUSY() false
#endif /* BUZZER */
#define AUDIO_RESET()
#define AUDIO_FLUSH()
#define PLAY_PHASE_OFF(phase)
#define PLAY_PHASE_ON(phase)
#define PLAY_SWITCH_MOVED(sw)
#define PLAY_LOGICAL_SWITCH_OFF(sw)
#define PLAY_LOGICAL_SWITCH_ON(sw)
#define PLAY_MODEL_NAME()
#define START_SILENCE_PERIOD()
#endif /* !AUDIO */
#if !defined(CPUARM)
#if defined(BUZZER)
inline void BUZZER_HEARTBEAT()
{
if (g_beepCnt) {
if (!beepAgainOrig) {
beepAgainOrig = g_beepCnt;
beepOn = true;
}
g_beepCnt--;
}
else {
if (beepAgain && beepAgainOrig) {
beepOn = !beepOn;
g_beepCnt = beepOn ? beepAgainOrig : 8;
if (beepOn) beepAgain--;
}
else {
beepAgainOrig = 0;
beepOn = false;
warble = false;
}
}
if (beepOn) {
warbleC = warble && !warbleC;
if (warbleC)
buzzerOff();
else
buzzerOn();
}
else {
buzzerOff();
}
}
#else // BUZZER
#define BUZZER_HEARTBEAT()
#endif // BUZZER
#endif // CPUARM
#endif // _BUZZER_H_

View file

@ -1,180 +1,180 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <string.h>
#include "opentx.h"
#if defined(SIMU) && !defined(SIMU_DISKIO)
#define __disk_read(...) (RES_OK)
#define __disk_write(...) (RES_OK)
#endif
#if 0 // set to 1 to enable traces
#define TRACE_DISK_CACHE(...) TRACE(__VA_ARGS__)
#else
#define TRACE_DISK_CACHE(...)
#endif
DiskCache diskCache;
DiskCacheBlock::DiskCacheBlock():
startSector(0),
endSector(0)
{
}
bool DiskCacheBlock::read(BYTE * buff, DWORD sector, UINT count)
{
if (sector >= startSector && (sector+count) <= endSector) {
TRACE_DISK_CACHE("\tcache read(%u, %u) from %p", (uint32_t)sector, (uint32_t)count, this);
memcpy(buff, data + ((sector - startSector) * BLOCK_SIZE), count * BLOCK_SIZE);
return true;
}
return false;
}
DRESULT DiskCacheBlock::fill(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
DRESULT res = __disk_read(drv, data, sector, DISK_CACHE_BLOCK_SECTORS);
if (res != RES_OK) {
return res;
}
startSector = sector;
endSector = sector + DISK_CACHE_BLOCK_SECTORS;
memcpy(buff, data, count * BLOCK_SIZE);
TRACE_DISK_CACHE("\tcache %p FILLED from read(%u, %u)", this, (uint32_t)sector, (uint32_t)count);
return RES_OK;
}
void DiskCacheBlock::free(DWORD sector, UINT count)
{
if (sector < endSector && (sector+count) > startSector) {
TRACE_DISK_CACHE("\tINVALIDATING disk cache block %p (%u)", this, startSector);
endSector = 0;
}
}
void DiskCacheBlock::free()
{
endSector = 0;
}
bool DiskCacheBlock::empty() const
{
return (endSector == 0);
}
DiskCache::DiskCache():
lastBlock(0)
{
stats.noHits = 0;
stats.noMisses = 0;
stats.noWrites = 0;
blocks = new DiskCacheBlock[DISK_CACHE_BLOCKS_NUM];
}
void DiskCache::clear()
{
lastBlock = 0;
stats.noHits = 0;
stats.noMisses = 0;
stats.noWrites = 0;
for (int n=0; n<DISK_CACHE_BLOCKS_NUM; ++n) {
blocks[n].free();
}
}
DRESULT DiskCache::read(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
// TODO: check if not caching first sectors would improve anything
// if (sector < 1000) {
// ++stats.noMisses;
// return __disk_read(drv, buff, sector, count);
// }
// if read is bigger than cache block, then read it directly without using cache
if (count > DISK_CACHE_BLOCK_SECTORS) {
TRACE_DISK_CACHE("\t\t big read(%u, %u)", (uint32_t)sector, (uint32_t)count);
return __disk_read(drv, buff, sector, count);
}
// if block + cache block size is beyond the end of the disk, then read it directly without using cache
if (sector+DISK_CACHE_BLOCK_SECTORS >= sdGetNoSectors()) {
TRACE_DISK_CACHE("\t\t cache would be beyond end of disk %u (%u)", (uint32_t)sector, sdGetNoSectors());
return __disk_read(drv, buff, sector, count);
}
for (int n=0; n<DISK_CACHE_BLOCKS_NUM; ++n) {
if (blocks[n].read(buff, sector, count)) {
++stats.noHits;
return RES_OK;
}
}
++stats.noMisses;
// find free block
for (int n=0; n<DISK_CACHE_BLOCKS_NUM; ++n) {
if (blocks[n].empty()) {
TRACE_DISK_CACHE("\t\t using free block");
return blocks[n].fill(drv, buff, sector, count);
}
}
// use next block (round robin)
// TODO: use better strategy to select which used block gets used here
if (++lastBlock >= DISK_CACHE_BLOCKS_NUM) {
lastBlock = 0;
}
return blocks[lastBlock].fill(drv, buff, sector, count);
}
DRESULT DiskCache::write(BYTE drv, const BYTE* buff, DWORD sector, UINT count)
{
++stats.noWrites;
for(int n=0; n < DISK_CACHE_BLOCKS_NUM; ++n) {
blocks[n].free(sector, count);
}
return __disk_write(drv, buff, sector, count);
}
const DiskCacheStats & DiskCache::getStats() const
{
return stats;
}
int DiskCache::getHitRate() const
{
uint32_t all = stats.noHits + stats.noMisses;
if (all == 0) return 0;
return (stats.noHits * 1000) / all;
}
DRESULT disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
return diskCache.read(drv, buff, sector, count);
}
DRESULT disk_write(BYTE drv, const BYTE * buff, DWORD sector, UINT count)
{
return diskCache.write(drv, buff, sector, count);
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <string.h>
#include "opentx.h"
#if defined(SIMU) && !defined(SIMU_DISKIO)
#define __disk_read(...) (RES_OK)
#define __disk_write(...) (RES_OK)
#endif
#if 0 // set to 1 to enable traces
#define TRACE_DISK_CACHE(...) TRACE(__VA_ARGS__)
#else
#define TRACE_DISK_CACHE(...)
#endif
DiskCache diskCache;
DiskCacheBlock::DiskCacheBlock():
startSector(0),
endSector(0)
{
}
bool DiskCacheBlock::read(BYTE * buff, DWORD sector, UINT count)
{
if (sector >= startSector && (sector+count) <= endSector) {
TRACE_DISK_CACHE("\tcache read(%u, %u) from %p", (uint32_t)sector, (uint32_t)count, this);
memcpy(buff, data + ((sector - startSector) * BLOCK_SIZE), count * BLOCK_SIZE);
return true;
}
return false;
}
DRESULT DiskCacheBlock::fill(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
DRESULT res = __disk_read(drv, data, sector, DISK_CACHE_BLOCK_SECTORS);
if (res != RES_OK) {
return res;
}
startSector = sector;
endSector = sector + DISK_CACHE_BLOCK_SECTORS;
memcpy(buff, data, count * BLOCK_SIZE);
TRACE_DISK_CACHE("\tcache %p FILLED from read(%u, %u)", this, (uint32_t)sector, (uint32_t)count);
return RES_OK;
}
void DiskCacheBlock::free(DWORD sector, UINT count)
{
if (sector < endSector && (sector+count) > startSector) {
TRACE_DISK_CACHE("\tINVALIDATING disk cache block %p (%u)", this, startSector);
endSector = 0;
}
}
void DiskCacheBlock::free()
{
endSector = 0;
}
bool DiskCacheBlock::empty() const
{
return (endSector == 0);
}
DiskCache::DiskCache():
lastBlock(0)
{
stats.noHits = 0;
stats.noMisses = 0;
stats.noWrites = 0;
blocks = new DiskCacheBlock[DISK_CACHE_BLOCKS_NUM];
}
void DiskCache::clear()
{
lastBlock = 0;
stats.noHits = 0;
stats.noMisses = 0;
stats.noWrites = 0;
for (int n=0; n<DISK_CACHE_BLOCKS_NUM; ++n) {
blocks[n].free();
}
}
DRESULT DiskCache::read(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
// TODO: check if not caching first sectors would improve anything
// if (sector < 1000) {
// ++stats.noMisses;
// return __disk_read(drv, buff, sector, count);
// }
// if read is bigger than cache block, then read it directly without using cache
if (count > DISK_CACHE_BLOCK_SECTORS) {
TRACE_DISK_CACHE("\t\t big read(%u, %u)", (uint32_t)sector, (uint32_t)count);
return __disk_read(drv, buff, sector, count);
}
// if block + cache block size is beyond the end of the disk, then read it directly without using cache
if (sector+DISK_CACHE_BLOCK_SECTORS >= sdGetNoSectors()) {
TRACE_DISK_CACHE("\t\t cache would be beyond end of disk %u (%u)", (uint32_t)sector, sdGetNoSectors());
return __disk_read(drv, buff, sector, count);
}
for (int n=0; n<DISK_CACHE_BLOCKS_NUM; ++n) {
if (blocks[n].read(buff, sector, count)) {
++stats.noHits;
return RES_OK;
}
}
++stats.noMisses;
// find free block
for (int n=0; n<DISK_CACHE_BLOCKS_NUM; ++n) {
if (blocks[n].empty()) {
TRACE_DISK_CACHE("\t\t using free block");
return blocks[n].fill(drv, buff, sector, count);
}
}
// use next block (round robin)
// TODO: use better strategy to select which used block gets used here
if (++lastBlock >= DISK_CACHE_BLOCKS_NUM) {
lastBlock = 0;
}
return blocks[lastBlock].fill(drv, buff, sector, count);
}
DRESULT DiskCache::write(BYTE drv, const BYTE* buff, DWORD sector, UINT count)
{
++stats.noWrites;
for(int n=0; n < DISK_CACHE_BLOCKS_NUM; ++n) {
blocks[n].free(sector, count);
}
return __disk_write(drv, buff, sector, count);
}
const DiskCacheStats & DiskCache::getStats() const
{
return stats;
}
int DiskCache::getHitRate() const
{
uint32_t all = stats.noHits + stats.noMisses;
if (all == 0) return 0;
return (stats.noHits * 1000) / all;
}
DRESULT disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
return diskCache.read(drv, buff, sector, count);
}
DRESULT disk_write(BYTE drv, const BYTE * buff, DWORD sector, UINT count)
{
return diskCache.write(drv, buff, sector, count);
}

View file

@ -1,74 +1,74 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _DISK_CACHE_H_
#define _DISK_CACHE_H_
#include "diskio.h"
#include "sdio_sd.h"
// tunable parameters
#define DISK_CACHE_BLOCKS_NUM 32 // no cache blocks
#define DISK_CACHE_BLOCK_SECTORS 16 // no sectors
#define DISK_CACHE_BLOCK_SIZE (DISK_CACHE_BLOCK_SECTORS * BLOCK_SIZE)
class DiskCacheBlock
{
public:
DiskCacheBlock();
bool read(BYTE* buff, DWORD sector, UINT count);
DRESULT fill(BYTE drv, BYTE* buff, DWORD sector, UINT count);
void free(DWORD sector, UINT count);
void free();
bool empty() const;
private:
uint8_t data[DISK_CACHE_BLOCK_SIZE];
DWORD startSector;
DWORD endSector;
};
struct DiskCacheStats
{
uint32_t noHits;
uint32_t noMisses;
uint32_t noWrites;
};
class DiskCache
{
public:
DiskCache();
DRESULT read(BYTE drv, BYTE* buff, DWORD sector, UINT count);
DRESULT write(BYTE drv, const BYTE* buff, DWORD sector, UINT count);
const DiskCacheStats & getStats() const;
int getHitRate() const;
void clear();
private:
DiskCacheStats stats;
uint32_t lastBlock;
DiskCacheBlock * blocks;
};
extern DiskCache diskCache;
#endif // _DISK_CACHE_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _DISK_CACHE_H_
#define _DISK_CACHE_H_
#include "diskio.h"
#include "sdio_sd.h"
// tunable parameters
#define DISK_CACHE_BLOCKS_NUM 32 // no cache blocks
#define DISK_CACHE_BLOCK_SECTORS 16 // no sectors
#define DISK_CACHE_BLOCK_SIZE (DISK_CACHE_BLOCK_SECTORS * BLOCK_SIZE)
class DiskCacheBlock
{
public:
DiskCacheBlock();
bool read(BYTE* buff, DWORD sector, UINT count);
DRESULT fill(BYTE drv, BYTE* buff, DWORD sector, UINT count);
void free(DWORD sector, UINT count);
void free();
bool empty() const;
private:
uint8_t data[DISK_CACHE_BLOCK_SIZE];
DWORD startSector;
DWORD endSector;
};
struct DiskCacheStats
{
uint32_t noHits;
uint32_t noMisses;
uint32_t noWrites;
};
class DiskCache
{
public:
DiskCache();
DRESULT read(BYTE drv, BYTE* buff, DWORD sector, UINT count);
DRESULT write(BYTE drv, const BYTE* buff, DWORD sector, UINT count);
const DiskCacheStats & getStats() const;
int getHitRate() const;
void clear();
private:
DiskCacheStats stats;
uint32_t lastBlock;
DiskCacheBlock * blocks;
};
extern DiskCache diskCache;
#endif // _DISK_CACHE_H_

View file

@ -1,82 +1,82 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _DMA_FIFO_H_
#define _DMA_FIFO_H_
#include "definitions.h"
template <int N>
class DMAFifo
{
public:
DMAFifo(DMA_Stream_TypeDef * stream):
stream(stream),
ridx(0)
{
}
void clear()
{
ridx = 0;
}
uint32_t size()
{
return N;
}
uint8_t last(int index)
{
return fifo[(2*N - stream->NDTR - index) & (N-1)];
}
bool isEmpty()
{
#if defined(SIMU)
return true;
#endif
return (ridx == N - stream->NDTR);
}
bool pop(uint8_t & element)
{
if (isEmpty()) {
return false;
}
else {
element = fifo[ridx];
ridx = (ridx+1) & (N-1);
return true;
}
}
uint8_t * buffer()
{
return fifo;
}
protected:
uint8_t fifo[N];
DMA_Stream_TypeDef * stream;
volatile uint32_t ridx;
};
#endif // _DMA_FIFO_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _DMA_FIFO_H_
#define _DMA_FIFO_H_
#include "definitions.h"
template <int N>
class DMAFifo
{
public:
DMAFifo(DMA_Stream_TypeDef * stream):
stream(stream),
ridx(0)
{
}
void clear()
{
ridx = 0;
}
uint32_t size()
{
return N;
}
uint8_t last(int index)
{
return fifo[(2*N - stream->NDTR - index) & (N-1)];
}
bool isEmpty()
{
#if defined(SIMU)
return true;
#endif
return (ridx == N - stream->NDTR);
}
bool pop(uint8_t & element)
{
if (isEmpty()) {
return false;
}
else {
element = fifo[ridx];
ridx = (ridx+1) & (N-1);
return true;
}
}
uint8_t * buffer()
{
return fifo;
}
protected:
uint8_t fifo[N];
DMA_Stream_TypeDef * stream;
volatile uint32_t ridx;
};
#endif // _DMA_FIFO_H_

View file

@ -1,105 +1,105 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _FIFO_H_
#define _FIFO_H_
template <class T, int N>
class Fifo
{
static_assert((N > 1) & !(N & (N - 1)), "Fifo size must be a power of two!");
public:
Fifo():
widx(0),
ridx(0)
{
}
void clear()
{
widx = ridx = 0;
}
void push(T element)
{
uint32_t next = (widx+1) & (N-1);
if (next != ridx) {
fifo[widx] = element;
widx = next;
}
}
bool pop(T & element)
{
if (isEmpty()) {
return false;
}
else {
element = fifo[ridx];
ridx = (ridx+1) & (N-1);
return true;
}
}
bool isEmpty() const
{
return (ridx == widx);
}
bool isFull()
{
uint32_t next = (widx+1) & (N-1);
return (next == ridx);
}
void flush()
{
while (!isEmpty()) {};
}
uint32_t size() const
{
return (N + widx - ridx) & (N-1);
}
uint32_t hasSpace(uint32_t n) const
{
return (N > (size() + n));
}
bool probe(T & element) const
{
if (isEmpty()) {
return false;
}
else {
element = fifo[ridx];
return true;
}
}
protected:
T fifo[N];
volatile uint32_t widx;
volatile uint32_t ridx;
};
#endif // _FIFO_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _FIFO_H_
#define _FIFO_H_
template <class T, int N>
class Fifo
{
static_assert((N > 1) & !(N & (N - 1)), "Fifo size must be a power of two!");
public:
Fifo():
widx(0),
ridx(0)
{
}
void clear()
{
widx = ridx = 0;
}
void push(T element)
{
uint32_t next = (widx+1) & (N-1);
if (next != ridx) {
fifo[widx] = element;
widx = next;
}
}
bool pop(T & element)
{
if (isEmpty()) {
return false;
}
else {
element = fifo[ridx];
ridx = (ridx+1) & (N-1);
return true;
}
}
bool isEmpty() const
{
return (ridx == widx);
}
bool isFull()
{
uint32_t next = (widx+1) & (N-1);
return (next == ridx);
}
void flush()
{
while (!isEmpty()) {};
}
uint32_t size() const
{
return (N + widx - ridx) & (N-1);
}
uint32_t hasSpace(uint32_t n) const
{
return (N > (size() + n));
}
bool probe(T & element) const
{
if (isEmpty()) {
return false;
}
else {
element = fifo[ridx];
return true;
}
}
protected:
T fifo[N];
volatile uint32_t widx;
volatile uint32_t ridx;
};
#endif // _FIFO_H_

View file

@ -1,56 +1,56 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _FONTS_H_
#define _FONTS_H_
#if defined(COLORLCD)
extern const uint16_t * const fontspecsTable[16];
extern const uint8_t * const fontsTable[16];
#if defined(PCBHORUS)
extern BitmapBuffer * fontCache[2];
void loadFontCache();
#endif
#else
extern const pm_uchar font_5x7[];
extern const pm_uchar font_10x14[];
#if defined(BOLD_FONT) && ((!defined(CPUM64) && !defined(PCBMEGA2560)) || defined(TELEMETRY_NONE)) && !defined(BOOT)
#define BOLD_SPECIFIC_FONT
extern const pm_uchar font_5x7_B[];
#endif
#if defined(CPUARM)
extern const pm_uchar font_3x5[];
extern const pm_uchar font_4x6[];
extern const pm_uchar font_8x10[];
extern const pm_uchar font_22x38_num[];
extern const pm_uchar font_5x7_extra[];
extern const pm_uchar font_10x14_extra[];
extern const pm_uchar font_4x6_extra[];
#endif
#endif
#endif // _FONTS_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _FONTS_H_
#define _FONTS_H_
#if defined(COLORLCD)
extern const uint16_t * const fontspecsTable[16];
extern const uint8_t * const fontsTable[16];
#if defined(PCBHORUS)
extern BitmapBuffer * fontCache[2];
void loadFontCache();
#endif
#else
extern const pm_uchar font_5x7[];
extern const pm_uchar font_10x14[];
#if defined(BOLD_FONT) && ((!defined(CPUM64) && !defined(PCBMEGA2560)) || defined(TELEMETRY_NONE)) && !defined(BOOT)
#define BOLD_SPECIFIC_FONT
extern const pm_uchar font_5x7_B[];
#endif
#if defined(CPUARM)
extern const pm_uchar font_3x5[];
extern const pm_uchar font_4x6[];
extern const pm_uchar font_8x10[];
extern const pm_uchar font_22x38_num[];
extern const pm_uchar font_5x7_extra[];
extern const pm_uchar font_10x14_extra[];
extern const pm_uchar font_4x6_extra[];
#endif
#endif
#endif // _FONTS_H_

File diff suppressed because it is too large Load diff

View file

@ -1,110 +1,110 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
const uint16_t font_tinsize_specs[] = {
#include "font_tinsize.specs"
};
const pm_uchar font_tinsize[] = {
#include "font_tinsize.lbm"
};
const uint16_t font_smlsize_specs[] = {
#include "font_smlsize.specs"
};
const pm_uchar font_smlsize[] = {
#include "font_smlsize.lbm"
};
const uint16_t font_stdsize_specs[] = {
#include "font_stdsize.specs"
};
const pm_uchar font_stdsize[] = {
#include "font_stdsize.lbm"
};
const uint16_t font_midsize_specs[] = {
#include "font_midsize.specs"
};
const pm_uchar font_midsize[] = {
#include "font_midsize.lbm"
};
const uint16_t font_dblsize_specs[] = {
#include "font_dblsize.specs"
};
const pm_uchar font_dblsize[] = {
#include "font_dblsize.lbm"
};
const uint16_t font_xxlsize_specs[] = {
#include "font_xxlsize.specs"
};
const pm_uchar font_xxlsize[] = {
#include "font_xxlsize.lbm"
};
const uint16_t font_stdsizebold_specs[] = {
#include "font_stdsizebold.specs"
};
const pm_uchar font_stdsizebold[] = {
#include "font_stdsizebold.lbm"
};
const uint16_t * const fontspecsTable[16] = {
font_stdsize_specs, font_tinsize_specs, font_smlsize_specs, font_midsize_specs, font_dblsize_specs, font_xxlsize_specs, font_stdsize_specs, font_stdsize_specs,
font_stdsizebold_specs, font_tinsize_specs, font_smlsize_specs, font_midsize_specs, font_dblsize_specs, font_xxlsize_specs, font_stdsize_specs, font_stdsize_specs
};
const uint8_t * const fontsTable[16] = {
font_stdsize, font_tinsize, font_smlsize, font_midsize, font_dblsize, font_xxlsize, font_stdsize, font_stdsize,
font_stdsizebold, font_tinsize, font_smlsize, font_midsize, font_dblsize, font_xxlsize, font_stdsize, font_stdsize
};
BitmapBuffer * fontCache[2] = { NULL, NULL };
BitmapBuffer * createFontCache(const uint8_t * font, LcdFlags fg, LcdFlags bg)
{
coord_t width = *((uint16_t *)font);
coord_t height = *(((uint16_t *)font)+1);
BitmapBuffer * buffer = new BitmapBuffer(BMP_RGB565, width, height);
if (buffer) {
buffer->clear(bg);
buffer->drawBitmapPattern(0, 0, font, fg);
}
return buffer;
}
void loadFontCache()
{
delete fontCache[0];
delete fontCache[1];
fontCache[0] = createFontCache(fontsTable[0], TEXT_COLOR, TEXT_BGCOLOR);
fontCache[1] = createFontCache(fontsTable[0], TEXT_INVERTED_COLOR, TEXT_INVERTED_BGCOLOR);
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
const uint16_t font_tinsize_specs[] = {
#include "font_tinsize.specs"
};
const pm_uchar font_tinsize[] = {
#include "font_tinsize.lbm"
};
const uint16_t font_smlsize_specs[] = {
#include "font_smlsize.specs"
};
const pm_uchar font_smlsize[] = {
#include "font_smlsize.lbm"
};
const uint16_t font_stdsize_specs[] = {
#include "font_stdsize.specs"
};
const pm_uchar font_stdsize[] = {
#include "font_stdsize.lbm"
};
const uint16_t font_midsize_specs[] = {
#include "font_midsize.specs"
};
const pm_uchar font_midsize[] = {
#include "font_midsize.lbm"
};
const uint16_t font_dblsize_specs[] = {
#include "font_dblsize.specs"
};
const pm_uchar font_dblsize[] = {
#include "font_dblsize.lbm"
};
const uint16_t font_xxlsize_specs[] = {
#include "font_xxlsize.specs"
};
const pm_uchar font_xxlsize[] = {
#include "font_xxlsize.lbm"
};
const uint16_t font_stdsizebold_specs[] = {
#include "font_stdsizebold.specs"
};
const pm_uchar font_stdsizebold[] = {
#include "font_stdsizebold.lbm"
};
const uint16_t * const fontspecsTable[16] = {
font_stdsize_specs, font_tinsize_specs, font_smlsize_specs, font_midsize_specs, font_dblsize_specs, font_xxlsize_specs, font_stdsize_specs, font_stdsize_specs,
font_stdsizebold_specs, font_tinsize_specs, font_smlsize_specs, font_midsize_specs, font_dblsize_specs, font_xxlsize_specs, font_stdsize_specs, font_stdsize_specs
};
const uint8_t * const fontsTable[16] = {
font_stdsize, font_tinsize, font_smlsize, font_midsize, font_dblsize, font_xxlsize, font_stdsize, font_stdsize,
font_stdsizebold, font_tinsize, font_smlsize, font_midsize, font_dblsize, font_xxlsize, font_stdsize, font_stdsize
};
BitmapBuffer * fontCache[2] = { NULL, NULL };
BitmapBuffer * createFontCache(const uint8_t * font, LcdFlags fg, LcdFlags bg)
{
coord_t width = *((uint16_t *)font);
coord_t height = *(((uint16_t *)font)+1);
BitmapBuffer * buffer = new BitmapBuffer(BMP_RGB565, width, height);
if (buffer) {
buffer->clear(bg);
buffer->drawBitmapPattern(0, 0, font, fg);
}
return buffer;
}
void loadFontCache()
{
delete fontCache[0];
delete fontCache[1];
fontCache[0] = createFontCache(fontsTable[0], TEXT_COLOR, TEXT_BGCOLOR);
fontCache[1] = createFontCache(fontsTable[0], TEXT_INVERTED_COLOR, TEXT_INVERTED_BGCOLOR);
}

View file

@ -1,153 +1,153 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
enum AboutScreens {
ABOUT_OPENTX,
ABOUT_HARDWARE,
ABOUT_BERTRAND,
ABOUT_ANDRE,
ABOUT_MIKE,
ABOUT_KJELL,
ABOUT_MARTIN,
ABOUT_ROMOLO,
ABOUT_ROB,
ABOUT_PARENTS,
ABOUT_END,
ABOUT_COUNT,
};
#define ABOUT_X 62
#define ABOUT_INDENT 16
bool menuAboutView(event_t event)
{
static uint8_t screenIndex = 0;
static uint8_t greyIndex = 0;
switch (event) {
case EVT_ENTRY:
screenIndex = 0;
greyIndex = 0;
break;
#if defined(PCBX12S)
case EVT_KEY_FIRST(KEY_PGDN):
#elif defined(PCBX10)
case EVT_KEY_BREAK(KEY_PGDN):
#endif
screenIndex < ABOUT_PARENTS ? screenIndex++ : screenIndex = ABOUT_OPENTX;
greyIndex = 0;
break;
case EVT_KEY_FIRST(KEY_PGUP):
#if defined(PCBX10)
case EVT_KEY_LONG(KEY_PGDN):
#endif
screenIndex > ABOUT_OPENTX ? screenIndex-- : screenIndex = ABOUT_PARENTS;
greyIndex = 0;
killEvents(event);
break;
case EVT_KEY_FIRST(KEY_EXIT):
chainMenu(menuMainView);
break;
}
theme->drawBackground();
theme->drawTopbarBackground(0);
uint8_t screenDuration = 150;
switch (screenIndex) {
case ABOUT_OPENTX:
case ABOUT_END:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_OPENTX_1);
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP + FH, STR_ABOUT_OPENTX_2);
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_OPENTX_3);
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_OPENTX_4);
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP + 4*FH, STR_ABOUT_OPENTX_5);
screenDuration = 255;
break;
case ABOUT_BERTRAND:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_BERTRAND_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_BERTRAND_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_BERTRAND_3);
break;
case ABOUT_ANDRE:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_ANDRE_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_ANDRE_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_ANDRE_3);
break;
case ABOUT_MIKE:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_MIKE_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_MIKE_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_MIKE_3);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_MIKE_4);
break;
case ABOUT_KJELL:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_KJELL_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_KJELL_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_KJELL_3);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_KJELL_4);
break;
case ABOUT_MARTIN:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_MARTIN_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_MARTIN_2);
break;
case ABOUT_ROMOLO:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_ROMOLO_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_ROMOLO_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_ROMOLO_3);
break;
case ABOUT_ROB:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_ROB_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_ROB_2);
break;
case ABOUT_HARDWARE:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, "FrSky", INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_HARDWARE_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_HARDWARE_3);
break;
case ABOUT_PARENTS:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_PARENTS_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_PARENTS_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_PARENTS_3);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_PARENTS_4);
screenDuration = 255;
break;
}
if (++greyIndex == screenDuration) {
greyIndex = 0;
if (++screenIndex == ABOUT_COUNT) {
chainMenu(menuMainView);
}
}
return true;
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
enum AboutScreens {
ABOUT_OPENTX,
ABOUT_HARDWARE,
ABOUT_BERTRAND,
ABOUT_ANDRE,
ABOUT_MIKE,
ABOUT_KJELL,
ABOUT_MARTIN,
ABOUT_ROMOLO,
ABOUT_ROB,
ABOUT_PARENTS,
ABOUT_END,
ABOUT_COUNT,
};
#define ABOUT_X 62
#define ABOUT_INDENT 16
bool menuAboutView(event_t event)
{
static uint8_t screenIndex = 0;
static uint8_t greyIndex = 0;
switch (event) {
case EVT_ENTRY:
screenIndex = 0;
greyIndex = 0;
break;
#if defined(PCBX12S)
case EVT_KEY_FIRST(KEY_PGDN):
#elif defined(PCBX10)
case EVT_KEY_BREAK(KEY_PGDN):
#endif
screenIndex < ABOUT_PARENTS ? screenIndex++ : screenIndex = ABOUT_OPENTX;
greyIndex = 0;
break;
case EVT_KEY_FIRST(KEY_PGUP):
#if defined(PCBX10)
case EVT_KEY_LONG(KEY_PGDN):
#endif
screenIndex > ABOUT_OPENTX ? screenIndex-- : screenIndex = ABOUT_PARENTS;
greyIndex = 0;
killEvents(event);
break;
case EVT_KEY_FIRST(KEY_EXIT):
chainMenu(menuMainView);
break;
}
theme->drawBackground();
theme->drawTopbarBackground(0);
uint8_t screenDuration = 150;
switch (screenIndex) {
case ABOUT_OPENTX:
case ABOUT_END:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_OPENTX_1);
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP + FH, STR_ABOUT_OPENTX_2);
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_OPENTX_3);
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_OPENTX_4);
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP + 4*FH, STR_ABOUT_OPENTX_5);
screenDuration = 255;
break;
case ABOUT_BERTRAND:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_BERTRAND_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_BERTRAND_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_BERTRAND_3);
break;
case ABOUT_ANDRE:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_ANDRE_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_ANDRE_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_ANDRE_3);
break;
case ABOUT_MIKE:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_MIKE_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_MIKE_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_MIKE_3);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_MIKE_4);
break;
case ABOUT_KJELL:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_KJELL_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_KJELL_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_KJELL_3);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_KJELL_4);
break;
case ABOUT_MARTIN:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_MARTIN_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_MARTIN_2);
break;
case ABOUT_ROMOLO:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_ROMOLO_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_ROMOLO_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_ROMOLO_3);
break;
case ABOUT_ROB:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_ROB_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_ROB_2);
break;
case ABOUT_HARDWARE:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, "FrSky", INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_HARDWARE_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_HARDWARE_3);
break;
case ABOUT_PARENTS:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_PARENTS_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_PARENTS_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_PARENTS_3);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_PARENTS_4);
screenDuration = 255;
break;
}
if (++greyIndex == screenDuration) {
greyIndex = 0;
if (++screenIndex == ABOUT_COUNT) {
chainMenu(menuMainView);
}
}
return true;
}

View file

@ -1,192 +1,192 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#define RECT_OFFSET 80
#define ROW_HEIGHT 42
#define BAR_HEIGHT 13
#define COLUMN_SIZE 200
#define X_OFFSET 25
#define Y_OFFSET 75
#define Y_OUTBAR 15
#define Y_MIXBAR 28
#define LEG_COLORBOX 15
#define VIEW_CHANNELS_LIMIT_PCT (g_model.extendedLimits ? LIMIT_EXT_PERCENT : 100)
bool menuChannelsMonitor(event_t event, uint8_t page);
bool menuLogicalSwitches(event_t);
template<int index>
bool menuChannelsMonitor(event_t event)
{
lastMonitorPage = e_MonChannelsFirst + index;
MENU(STR_MONITOR_CHANNELS[index], MONITOR_ICONS, menuTabMonitors, lastMonitorPage, 0, { 0 });
return menuChannelsMonitor(event, index);
}
const MenuHandlerFunc menuTabMonitors[] PROGMEM = {
menuChannelsMonitor<0>,
menuChannelsMonitor<1>,
menuChannelsMonitor<2>,
menuChannelsMonitor<3>,
menuLogicalSwitches
};
uint8_t lastMonitorPage = 0;
uint16_t posOnBar(int16_t value_to100)
{
return divRoundClosest((value_to100 + VIEW_CHANNELS_LIMIT_PCT) * COLUMN_SIZE, VIEW_CHANNELS_LIMIT_PCT * 2);
}
void drawOutputBarLimits(coord_t left, coord_t right, coord_t y)
{
lcd->drawSolidVerticalLine(left, y, BAR_HEIGHT, TEXT_COLOR);
lcd->drawSolidHorizontalLine(left, y, 3, TEXT_COLOR);
lcd->drawSolidHorizontalLine(left, y + BAR_HEIGHT - 1, 3, TEXT_COLOR);
lcd->drawSolidVerticalLine(--right, y, BAR_HEIGHT, TEXT_COLOR);
lcd->drawSolidHorizontalLine(right - 3, y, 3, TEXT_COLOR);
lcd->drawSolidHorizontalLine(right - 3, y + BAR_HEIGHT - 1, 3, TEXT_COLOR);
}
void drawSingleMixerBar(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t channel)
{
int16_t chanVal = calcRESXto100(ex_chans[channel]);
const int16_t displayVal = chanVal;
// this could be handled nicer, but slower, by checking actual range for this mixer
chanVal = limit<int16_t>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
lcdDrawSolidFilledRect(x, y, w, h, BARGRAPH_BGCOLOR);
if (chanVal > 0) {
lcdDrawSolidFilledRect(x + w / 2, y, divRoundClosest(chanVal * w, VIEW_CHANNELS_LIMIT_PCT * 2), h, BARGRAPH2_COLOR);
lcdDrawNumber(x - 10 + w / 2, y - 2, displayVal, SMLSIZE | TEXT_COLOR | RIGHT, 0, NULL, "%");
}
else if (chanVal < 0) {
const uint16_t endpoint = x + w / 2;
const uint16_t size = divRoundClosest(-chanVal * w, VIEW_CHANNELS_LIMIT_PCT * 2);
lcdDrawSolidFilledRect(endpoint - size, y, size, h, BARGRAPH2_COLOR);
lcdDrawNumber(x + 10 + w / 2, y - 2, displayVal, SMLSIZE | TEXT_COLOR, 0, NULL, "%");
}
lcd->drawSolidVerticalLine(x + w / 2, y, h, TEXT_COLOR);
}
void drawSingleOutputBar(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t channel)
{
int16_t chanVal = calcRESXto100(channelOutputs[channel]);
int16_t displayVal = chanVal;
chanVal = limit<int16_t>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
lcdDrawSolidFilledRect(x, y, w, h, BARGRAPH_BGCOLOR);
if (chanVal > 0) {
lcdDrawSolidFilledRect(x + w / 2, y, divRoundClosest(chanVal * w, VIEW_CHANNELS_LIMIT_PCT * 2), h, BARGRAPH1_COLOR);
lcdDrawNumber(x - 10 + w / 2, y - 2, displayVal, SMLSIZE | TEXT_COLOR | RIGHT, 0, NULL, "%");
}
else if (chanVal < 0) {
uint16_t endpoint = x + w / 2;
uint16_t size = divRoundClosest(-chanVal * w, VIEW_CHANNELS_LIMIT_PCT * 2);
lcdDrawSolidFilledRect(endpoint - size, y, size, h, BARGRAPH1_COLOR);
lcdDrawNumber(x + 10 + w / 2, y - 2, displayVal, SMLSIZE | TEXT_COLOR, 0, NULL, "%");
}
lcd->drawSolidVerticalLine(x + w / 2, y, h, TEXT_COLOR);
}
void drawComboOutputBar(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t channel)
{
char chanString[] = "Ch32 ";
int16_t chanVal = calcRESXto100(channelOutputs[channel]);
LimitData * ld = limitAddress(channel);
int usValue = PPM_CH_CENTER(channel) + channelOutputs[channel] / 2;
const uint16_t limPos = ld ? posOnBar(calcRESXto100(ld->offset)) : 0;
uint16_t valPos;
strAppendSigned(&chanString[2], channel + 1, 2);
lcdDrawText(x, y, chanString, SMLSIZE | TEXT_COLOR | LEFT);
lcdDrawSizedText(x + 45, y, g_model.limitData[channel].name, sizeof(g_model.limitData[channel].name), SMLSIZE | TEXT_COLOR | LEFT | ZCHAR);
lcdDrawNumber(x + w, y, usValue, SMLSIZE | TEXT_COLOR | RIGHT, 0, NULL, STR_US);
lcdDrawSolidFilledRect(x, y + Y_OUTBAR, w, h, BARGRAPH_BGCOLOR);
lcd->drawSolidVerticalLine(x + limPos, y + Y_OUTBAR, h, MAINVIEW_GRAPHICS_COLOR);
if (chanVal > 0)
lcdDrawNumber(x - 10 + w / 2, y + h, chanVal, SMLSIZE | TEXT_COLOR | RIGHT, 0, NULL, "%");
else
lcdDrawNumber(x + 10 + w / 2, y + h, chanVal, SMLSIZE | TEXT_COLOR, 0, NULL, "%");
chanVal = limit<int16_t>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
valPos = posOnBar(chanVal);
if (valPos > limPos) {
lcdDrawSolidFilledRect(x + limPos, y + Y_OUTBAR, valPos - limPos, h, BARGRAPH1_COLOR);
}
else if (valPos < limPos) {
uint16_t endpoint = x + limPos;
uint16_t size = limPos - valPos;
lcdDrawSolidFilledRect(endpoint - size, y + Y_OUTBAR, size, h, BARGRAPH1_COLOR);
}
if (ld && ld->revert) {
drawOutputBarLimits(x + posOnBar(-100 - ld->max / 10), x + posOnBar(100 - ld->min / 10), y + Y_OUTBAR);
lcd->drawBitmap(x - X_OFFSET + 7, y + 25, chanMonInvertedBitmap);
}
else if (ld) {
drawOutputBarLimits(x + posOnBar(-100 + ld->min / 10), x + posOnBar(100 + ld->max / 10), y + Y_OUTBAR);
}
#if defined(OVERRIDE_CHANNEL_FUNCTION)
if (safetyCh[channel] != OVERRIDE_CHANNEL_UNDEFINED)
lcd->drawBitmap(x - X_OFFSET + 7, y + 7, chanMonLockedBitmap);
#endif
lcd->drawSolidVerticalLine(x + w / 2, y + Y_OUTBAR, h, TEXT_COLOR);
}
coord_t drawChannelsMonitorLegend(coord_t x, const pm_char * s, int color)
{
lcdDrawSolidFilledRect(x, MENU_FOOTER_TOP + 2, LEG_COLORBOX + 2, LEG_COLORBOX + 2, BARGRAPH_BGCOLOR);
lcdDrawSolidFilledRect(x + 1, MENU_FOOTER_TOP + 3, LEG_COLORBOX, LEG_COLORBOX, color);
lcdDrawText(x + 20, MENU_FOOTER_TOP, s, TEXT_STATUSBAR_COLOR);
return x + 25 + getTextWidth(s);
}
bool menuChannelsMonitor(event_t event, uint8_t page)
{
uint8_t channel = 8 * page;
coord_t x, y = Y_OFFSET;
x = drawChannelsMonitorLegend(MENUS_MARGIN_LEFT, STR_MONITOR_OUTPUT_DESC, BARGRAPH1_COLOR);
drawChannelsMonitorLegend(x, STR_MONITOR_MIXER_DESC, BARGRAPH2_COLOR);
x = X_OFFSET;
for (uint8_t i = 0; i < 8; i++, channel++, y += ROW_HEIGHT) {
if (i == 4) {
x = 1 + LCD_W / 2 + X_OFFSET;
y = Y_OFFSET;
}
drawComboOutputBar(x, y, COLUMN_SIZE, BAR_HEIGHT, channel);
drawSingleMixerBar(x, y + Y_MIXBAR + 1, COLUMN_SIZE, BAR_HEIGHT, channel);
}
return true;
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#define RECT_OFFSET 80
#define ROW_HEIGHT 42
#define BAR_HEIGHT 13
#define COLUMN_SIZE 200
#define X_OFFSET 25
#define Y_OFFSET 75
#define Y_OUTBAR 15
#define Y_MIXBAR 28
#define LEG_COLORBOX 15
#define VIEW_CHANNELS_LIMIT_PCT (g_model.extendedLimits ? LIMIT_EXT_PERCENT : 100)
bool menuChannelsMonitor(event_t event, uint8_t page);
bool menuLogicalSwitches(event_t);
template<int index>
bool menuChannelsMonitor(event_t event)
{
lastMonitorPage = e_MonChannelsFirst + index;
MENU(STR_MONITOR_CHANNELS[index], MONITOR_ICONS, menuTabMonitors, lastMonitorPage, 0, { 0 });
return menuChannelsMonitor(event, index);
}
const MenuHandlerFunc menuTabMonitors[] PROGMEM = {
menuChannelsMonitor<0>,
menuChannelsMonitor<1>,
menuChannelsMonitor<2>,
menuChannelsMonitor<3>,
menuLogicalSwitches
};
uint8_t lastMonitorPage = 0;
uint16_t posOnBar(int16_t value_to100)
{
return divRoundClosest((value_to100 + VIEW_CHANNELS_LIMIT_PCT) * COLUMN_SIZE, VIEW_CHANNELS_LIMIT_PCT * 2);
}
void drawOutputBarLimits(coord_t left, coord_t right, coord_t y)
{
lcd->drawSolidVerticalLine(left, y, BAR_HEIGHT, TEXT_COLOR);
lcd->drawSolidHorizontalLine(left, y, 3, TEXT_COLOR);
lcd->drawSolidHorizontalLine(left, y + BAR_HEIGHT - 1, 3, TEXT_COLOR);
lcd->drawSolidVerticalLine(--right, y, BAR_HEIGHT, TEXT_COLOR);
lcd->drawSolidHorizontalLine(right - 3, y, 3, TEXT_COLOR);
lcd->drawSolidHorizontalLine(right - 3, y + BAR_HEIGHT - 1, 3, TEXT_COLOR);
}
void drawSingleMixerBar(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t channel)
{
int16_t chanVal = calcRESXto100(ex_chans[channel]);
const int16_t displayVal = chanVal;
// this could be handled nicer, but slower, by checking actual range for this mixer
chanVal = limit<int16_t>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
lcdDrawSolidFilledRect(x, y, w, h, BARGRAPH_BGCOLOR);
if (chanVal > 0) {
lcdDrawSolidFilledRect(x + w / 2, y, divRoundClosest(chanVal * w, VIEW_CHANNELS_LIMIT_PCT * 2), h, BARGRAPH2_COLOR);
lcdDrawNumber(x - 10 + w / 2, y - 2, displayVal, SMLSIZE | TEXT_COLOR | RIGHT, 0, NULL, "%");
}
else if (chanVal < 0) {
const uint16_t endpoint = x + w / 2;
const uint16_t size = divRoundClosest(-chanVal * w, VIEW_CHANNELS_LIMIT_PCT * 2);
lcdDrawSolidFilledRect(endpoint - size, y, size, h, BARGRAPH2_COLOR);
lcdDrawNumber(x + 10 + w / 2, y - 2, displayVal, SMLSIZE | TEXT_COLOR, 0, NULL, "%");
}
lcd->drawSolidVerticalLine(x + w / 2, y, h, TEXT_COLOR);
}
void drawSingleOutputBar(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t channel)
{
int16_t chanVal = calcRESXto100(channelOutputs[channel]);
int16_t displayVal = chanVal;
chanVal = limit<int16_t>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
lcdDrawSolidFilledRect(x, y, w, h, BARGRAPH_BGCOLOR);
if (chanVal > 0) {
lcdDrawSolidFilledRect(x + w / 2, y, divRoundClosest(chanVal * w, VIEW_CHANNELS_LIMIT_PCT * 2), h, BARGRAPH1_COLOR);
lcdDrawNumber(x - 10 + w / 2, y - 2, displayVal, SMLSIZE | TEXT_COLOR | RIGHT, 0, NULL, "%");
}
else if (chanVal < 0) {
uint16_t endpoint = x + w / 2;
uint16_t size = divRoundClosest(-chanVal * w, VIEW_CHANNELS_LIMIT_PCT * 2);
lcdDrawSolidFilledRect(endpoint - size, y, size, h, BARGRAPH1_COLOR);
lcdDrawNumber(x + 10 + w / 2, y - 2, displayVal, SMLSIZE | TEXT_COLOR, 0, NULL, "%");
}
lcd->drawSolidVerticalLine(x + w / 2, y, h, TEXT_COLOR);
}
void drawComboOutputBar(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t channel)
{
char chanString[] = "Ch32 ";
int16_t chanVal = calcRESXto100(channelOutputs[channel]);
LimitData * ld = limitAddress(channel);
int usValue = PPM_CH_CENTER(channel) + channelOutputs[channel] / 2;
const uint16_t limPos = ld ? posOnBar(calcRESXto100(ld->offset)) : 0;
uint16_t valPos;
strAppendSigned(&chanString[2], channel + 1, 2);
lcdDrawText(x, y, chanString, SMLSIZE | TEXT_COLOR | LEFT);
lcdDrawSizedText(x + 45, y, g_model.limitData[channel].name, sizeof(g_model.limitData[channel].name), SMLSIZE | TEXT_COLOR | LEFT | ZCHAR);
lcdDrawNumber(x + w, y, usValue, SMLSIZE | TEXT_COLOR | RIGHT, 0, NULL, STR_US);
lcdDrawSolidFilledRect(x, y + Y_OUTBAR, w, h, BARGRAPH_BGCOLOR);
lcd->drawSolidVerticalLine(x + limPos, y + Y_OUTBAR, h, MAINVIEW_GRAPHICS_COLOR);
if (chanVal > 0)
lcdDrawNumber(x - 10 + w / 2, y + h, chanVal, SMLSIZE | TEXT_COLOR | RIGHT, 0, NULL, "%");
else
lcdDrawNumber(x + 10 + w / 2, y + h, chanVal, SMLSIZE | TEXT_COLOR, 0, NULL, "%");
chanVal = limit<int16_t>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
valPos = posOnBar(chanVal);
if (valPos > limPos) {
lcdDrawSolidFilledRect(x + limPos, y + Y_OUTBAR, valPos - limPos, h, BARGRAPH1_COLOR);
}
else if (valPos < limPos) {
uint16_t endpoint = x + limPos;
uint16_t size = limPos - valPos;
lcdDrawSolidFilledRect(endpoint - size, y + Y_OUTBAR, size, h, BARGRAPH1_COLOR);
}
if (ld && ld->revert) {
drawOutputBarLimits(x + posOnBar(-100 - ld->max / 10), x + posOnBar(100 - ld->min / 10), y + Y_OUTBAR);
lcd->drawBitmap(x - X_OFFSET + 7, y + 25, chanMonInvertedBitmap);
}
else if (ld) {
drawOutputBarLimits(x + posOnBar(-100 + ld->min / 10), x + posOnBar(100 + ld->max / 10), y + Y_OUTBAR);
}
#if defined(OVERRIDE_CHANNEL_FUNCTION)
if (safetyCh[channel] != OVERRIDE_CHANNEL_UNDEFINED)
lcd->drawBitmap(x - X_OFFSET + 7, y + 7, chanMonLockedBitmap);
#endif
lcd->drawSolidVerticalLine(x + w / 2, y + Y_OUTBAR, h, TEXT_COLOR);
}
coord_t drawChannelsMonitorLegend(coord_t x, const pm_char * s, int color)
{
lcdDrawSolidFilledRect(x, MENU_FOOTER_TOP + 2, LEG_COLORBOX + 2, LEG_COLORBOX + 2, BARGRAPH_BGCOLOR);
lcdDrawSolidFilledRect(x + 1, MENU_FOOTER_TOP + 3, LEG_COLORBOX, LEG_COLORBOX, color);
lcdDrawText(x + 20, MENU_FOOTER_TOP, s, TEXT_STATUSBAR_COLOR);
return x + 25 + getTextWidth(s);
}
bool menuChannelsMonitor(event_t event, uint8_t page)
{
uint8_t channel = 8 * page;
coord_t x, y = Y_OFFSET;
x = drawChannelsMonitorLegend(MENUS_MARGIN_LEFT, STR_MONITOR_OUTPUT_DESC, BARGRAPH1_COLOR);
drawChannelsMonitorLegend(x, STR_MONITOR_MIXER_DESC, BARGRAPH2_COLOR);
x = X_OFFSET;
for (uint8_t i = 0; i < 8; i++, channel++, y += ROW_HEIGHT) {
if (i == 4) {
x = 1 + LCD_W / 2 + X_OFFSET;
y = Y_OFFSET;
}
drawComboOutputBar(x, y, COLUMN_SIZE, BAR_HEIGHT, channel);
drawSingleMixerBar(x, y + Y_MIXBAR + 1, COLUMN_SIZE, BAR_HEIGHT, channel);
}
return true;
}

View file

@ -1,238 +1,238 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#include "stamp.h"
#define MENU_STATS_COLUMN1 (MENUS_MARGIN_LEFT + 120)
#define MENU_STATS_COLUMN2 (LCD_W/2)
#define MENU_STATS_COLUMN3 (LCD_W/2 + 120)
bool menuStatsGraph(event_t event)
{
switch(event) {
case EVT_KEY_LONG(KEY_ENTER):
g_eeGeneral.globalTimer = 0;
storageDirty(EE_GENERAL);
sessionTimer = 0;
killEvents(event);
break;
}
MENU(STR_STATISTICS, STATS_ICONS, menuTabStats, e_StatsGraph, 0, { 0 });
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP, "Session");
drawTimer(MENU_STATS_COLUMN1, MENU_CONTENT_TOP, sessionTimer, TIMEHOUR);
lcdDrawText(MENU_STATS_COLUMN2, MENU_CONTENT_TOP, "Battery");
drawTimer(MENU_STATS_COLUMN3, MENU_CONTENT_TOP, g_eeGeneral.globalTimer+sessionTimer, TIMEHOUR);
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+FH, "Throttle");
drawTimer(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+FH, s_timeCumThr, TIMEHOUR);
lcdDrawText(MENU_STATS_COLUMN2, MENU_CONTENT_TOP+FH, "Throttle %", TIMEHOUR);
drawTimer(MENU_STATS_COLUMN3, MENU_CONTENT_TOP+FH, s_timeCum16ThrP/16, TIMEHOUR);
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+2*FH, "Timers");
lcdDrawText(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+2*FH, "[1]", HEADER_COLOR);
drawTimer(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, timersStates[0].val, TIMEHOUR);
lcdDrawText(MENU_STATS_COLUMN2, MENU_CONTENT_TOP+2*FH, "[2]", HEADER_COLOR);
drawTimer(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, timersStates[1].val, TIMEHOUR);
#if TIMERS > 2
lcdDrawText(MENU_STATS_COLUMN3, MENU_CONTENT_TOP+2*FH, "[3]", HEADER_COLOR);
drawTimer(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, timersStates[2].val, TIMEHOUR);
#endif
const coord_t x = 10;
const coord_t y = 240;
lcdDrawHorizontalLine(x-3, y, MAXTRACE+3+3, SOLID, TEXT_COLOR);
lcdDrawVerticalLine(x, y-96, 96+3, SOLID, TEXT_COLOR);
for (coord_t i=0; i<MAXTRACE; i+=6) {
lcdDrawVerticalLine(x+i, y-1, 3, SOLID, TEXT_COLOR);
}
uint16_t traceRd = s_traceWr > MAXTRACE ? s_traceWr - MAXTRACE : 0;
coord_t prev_yv = (coord_t)-1;
for (coord_t i=1; i<=MAXTRACE && traceRd<s_traceWr; i++, traceRd++) {
uint8_t h = s_traceBuf[traceRd % MAXTRACE];
coord_t yv = y - 2 - 3*h;
if (prev_yv != (coord_t)-1) {
if (prev_yv < yv) {
for (int y=prev_yv; y<=yv; y++) {
lcdDrawBitmapPattern(x + i - 3, y, LBM_POINT, TEXT_COLOR);
}
}
else {
for (int y=yv; y<=prev_yv; y++) {
lcdDrawBitmapPattern(x + i - 3, y, LBM_POINT, TEXT_COLOR);
}
}
}
else {
lcdDrawBitmapPattern(x + i - 3, yv, LBM_POINT, TEXT_COLOR);
}
prev_yv = yv;
}
lcdDrawText(LCD_W/2, MENU_FOOTER_TOP+2, STR_MENUTORESET, CENTERED);
return true;
}
bool menuStatsDebug(event_t event)
{
switch(event)
{
case EVT_KEY_FIRST(KEY_ENTER):
maxMixerDuration = 0;
#if defined(LUA)
maxLuaInterval = 0;
maxLuaDuration = 0;
#endif
break;
}
MENU("Debug", STATS_ICONS, menuTabStats, e_StatsDebug, 0, { 0 });
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP, "Free Mem");
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP, availableMemory(), LEFT, 0, NULL, "b");
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+FH, STR_TMIXMAXMS);
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+FH, DURATION_MS_PREC2(maxMixerDuration), PREC2|LEFT, 0, NULL, "ms");
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+2*FH, STR_FREESTACKMINB);
lcdDrawText(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+2*FH+1, "[Menus]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, menusStack.available(), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+2*FH+1, "[Mix]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, mixerStack.available(), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+2*FH+1, "[Audio]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, audioStack.available(), LEFT);
int line = 3;
#if defined(DISK_CACHE)
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "SD cache hits");
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH, diskCache.getHitRate(), PREC1|LEFT, 0, NULL, "%");
++line;
#endif
#if defined(LUA)
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua duration");
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH, 10*maxLuaDuration, LEFT, 0, NULL, "ms");
++line;
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua interval");
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH, 10*maxLuaInterval, LEFT, 0, NULL, "ms");
++line;
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua memory");
lcdDrawText(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH+1, "[S]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaGetMemUsed(lsScripts), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+line*FH+1, "[W]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaGetMemUsed(lsWidgets), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+line*FH+1, "[B]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaExtraMemoryUsage, LEFT);
++line;
#endif
lcdDrawText(LCD_W/2, MENU_FOOTER_TOP+2, STR_MENUTORESET, CENTERED);
return true;
}
bool menuStatsAnalogs(event_t event)
{
MENU("Analogs", STATS_ICONS, menuTabStats, e_StatsAnalogs, 0, { 0 });
for (uint8_t i=0; i<NUM_ANALOGS; i++) {
coord_t y = MENU_CONTENT_TOP + (i/2)*FH;
coord_t x = MENUS_MARGIN_LEFT + (i & 1 ? LCD_W/2 : 0);
lcdDrawNumber(x, y, i+1, LEADING0|LEFT, 2, NULL, ":");
lcdDrawHexNumber(x+40, y, anaIn(i));
#if defined(JITTER_MEASURE)
lcdDrawNumber(x+100, y, rawJitter[i].get());
lcdDrawNumber(x+140, y, avgJitter[i].get());
lcdDrawNumber(x+180, y, (int16_t)calibratedAnalogs[CONVERT_MODE(i)]*250/256, PREC1);
#else
if (i < NUM_STICKS+NUM_POTS+NUM_SLIDERS)
lcdDrawNumber(x+100, y, (int16_t)calibratedAnalogs[CONVERT_MODE(i)]*25/256);
else if (i >= MOUSE1)
lcdDrawNumber(x+100, y, (int16_t)calibratedAnalogs[CALIBRATED_MOUSE1+i-MOUSE1]*25/256);
#endif
}
// SWR
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+7*FH, "RAS");
lcdDrawNumber(MENUS_MARGIN_LEFT+100, MENU_CONTENT_TOP+7*FH, telemetryData.swr.value);
return true;
}
#if defined(DEBUG_TRACE_BUFFER)
#define STATS_TRACES_INDEX_POS MENUS_MARGIN_LEFT
#define STATS_TRACES_TIME_POS MENUS_MARGIN_LEFT + 4*10
#define STATS_TRACES_EVENT_POS MENUS_MARGIN_LEFT + 14*10
#define STATS_TRACES_DATA_POS MENUS_MARGIN_LEFT + 20*10
bool menuStatsTraces(event_t event)
{
switch(event)
{
case EVT_KEY_LONG(KEY_ENTER):
dumpTraceBuffer();
killEvents(event);
break;
}
SIMPLE_MENU("", STATS_ICONS, menuTabStats, e_StatsTraces, TRACE_BUFFER_LEN);
uint8_t k = 0;
int8_t sub = menuVerticalPosition;
lcdDrawChar(STATS_TRACES_INDEX_POS, MENU_TITLE_TOP+2, '#', MENU_TITLE_COLOR);
lcdDrawText(STATS_TRACES_TIME_POS, MENU_TITLE_TOP+2, "Time", MENU_TITLE_COLOR);
lcdDrawText(STATS_TRACES_EVENT_POS, MENU_TITLE_TOP+2, "Event", MENU_TITLE_COLOR);
lcdDrawText(STATS_TRACES_DATA_POS, MENU_TITLE_TOP+2, "Data", MENU_TITLE_COLOR);
for (uint8_t i=0; i<NUM_BODY_LINES; i++) {
coord_t y = MENU_CONTENT_TOP + i * FH;
k = i+menuVerticalOffset;
// item
lcdDrawNumber(STATS_TRACES_INDEX_POS, y, k, LEFT | (sub==k ? INVERS : 0));
const struct TraceElement * te = getTraceElement(k);
if (te) {
// time
putstime_t tme = te->time % SECS_PER_DAY;
drawTimer(STATS_TRACES_TIME_POS, y, tme, TIMEHOUR|LEFT);
// event
lcdDrawNumber(STATS_TRACES_EVENT_POS, y, te->event, LEADING0|LEFT, 3);
// data
lcdDrawSizedText(STATS_TRACES_DATA_POS, y, "0x", 2);
lcdDrawHexNumber(lcdNextPos, y, (uint16_t)(te->data >> 16));
lcdDrawHexNumber(lcdNextPos, y, (uint16_t)(te->data & 0xFFFF));
}
}
return true;
}
#endif // defined(DEBUG_TRACE_BUFFER)
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#include "stamp.h"
#define MENU_STATS_COLUMN1 (MENUS_MARGIN_LEFT + 120)
#define MENU_STATS_COLUMN2 (LCD_W/2)
#define MENU_STATS_COLUMN3 (LCD_W/2 + 120)
bool menuStatsGraph(event_t event)
{
switch(event) {
case EVT_KEY_LONG(KEY_ENTER):
g_eeGeneral.globalTimer = 0;
storageDirty(EE_GENERAL);
sessionTimer = 0;
killEvents(event);
break;
}
MENU(STR_STATISTICS, STATS_ICONS, menuTabStats, e_StatsGraph, 0, { 0 });
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP, "Session");
drawTimer(MENU_STATS_COLUMN1, MENU_CONTENT_TOP, sessionTimer, TIMEHOUR);
lcdDrawText(MENU_STATS_COLUMN2, MENU_CONTENT_TOP, "Battery");
drawTimer(MENU_STATS_COLUMN3, MENU_CONTENT_TOP, g_eeGeneral.globalTimer+sessionTimer, TIMEHOUR);
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+FH, "Throttle");
drawTimer(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+FH, s_timeCumThr, TIMEHOUR);
lcdDrawText(MENU_STATS_COLUMN2, MENU_CONTENT_TOP+FH, "Throttle %", TIMEHOUR);
drawTimer(MENU_STATS_COLUMN3, MENU_CONTENT_TOP+FH, s_timeCum16ThrP/16, TIMEHOUR);
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+2*FH, "Timers");
lcdDrawText(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+2*FH, "[1]", HEADER_COLOR);
drawTimer(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, timersStates[0].val, TIMEHOUR);
lcdDrawText(MENU_STATS_COLUMN2, MENU_CONTENT_TOP+2*FH, "[2]", HEADER_COLOR);
drawTimer(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, timersStates[1].val, TIMEHOUR);
#if TIMERS > 2
lcdDrawText(MENU_STATS_COLUMN3, MENU_CONTENT_TOP+2*FH, "[3]", HEADER_COLOR);
drawTimer(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, timersStates[2].val, TIMEHOUR);
#endif
const coord_t x = 10;
const coord_t y = 240;
lcdDrawHorizontalLine(x-3, y, MAXTRACE+3+3, SOLID, TEXT_COLOR);
lcdDrawVerticalLine(x, y-96, 96+3, SOLID, TEXT_COLOR);
for (coord_t i=0; i<MAXTRACE; i+=6) {
lcdDrawVerticalLine(x+i, y-1, 3, SOLID, TEXT_COLOR);
}
uint16_t traceRd = s_traceWr > MAXTRACE ? s_traceWr - MAXTRACE : 0;
coord_t prev_yv = (coord_t)-1;
for (coord_t i=1; i<=MAXTRACE && traceRd<s_traceWr; i++, traceRd++) {
uint8_t h = s_traceBuf[traceRd % MAXTRACE];
coord_t yv = y - 2 - 3*h;
if (prev_yv != (coord_t)-1) {
if (prev_yv < yv) {
for (int y=prev_yv; y<=yv; y++) {
lcdDrawBitmapPattern(x + i - 3, y, LBM_POINT, TEXT_COLOR);
}
}
else {
for (int y=yv; y<=prev_yv; y++) {
lcdDrawBitmapPattern(x + i - 3, y, LBM_POINT, TEXT_COLOR);
}
}
}
else {
lcdDrawBitmapPattern(x + i - 3, yv, LBM_POINT, TEXT_COLOR);
}
prev_yv = yv;
}
lcdDrawText(LCD_W/2, MENU_FOOTER_TOP+2, STR_MENUTORESET, CENTERED);
return true;
}
bool menuStatsDebug(event_t event)
{
switch(event)
{
case EVT_KEY_FIRST(KEY_ENTER):
maxMixerDuration = 0;
#if defined(LUA)
maxLuaInterval = 0;
maxLuaDuration = 0;
#endif
break;
}
MENU("Debug", STATS_ICONS, menuTabStats, e_StatsDebug, 0, { 0 });
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP, "Free Mem");
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP, availableMemory(), LEFT, 0, NULL, "b");
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+FH, STR_TMIXMAXMS);
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+FH, DURATION_MS_PREC2(maxMixerDuration), PREC2|LEFT, 0, NULL, "ms");
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+2*FH, STR_FREESTACKMINB);
lcdDrawText(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+2*FH+1, "[Menus]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, menusStack.available(), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+2*FH+1, "[Mix]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, mixerStack.available(), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+2*FH+1, "[Audio]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+2*FH, audioStack.available(), LEFT);
int line = 3;
#if defined(DISK_CACHE)
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "SD cache hits");
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH, diskCache.getHitRate(), PREC1|LEFT, 0, NULL, "%");
++line;
#endif
#if defined(LUA)
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua duration");
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH, 10*maxLuaDuration, LEFT, 0, NULL, "ms");
++line;
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua interval");
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH, 10*maxLuaInterval, LEFT, 0, NULL, "ms");
++line;
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua memory");
lcdDrawText(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH+1, "[S]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaGetMemUsed(lsScripts), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+line*FH+1, "[W]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaGetMemUsed(lsWidgets), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+line*FH+1, "[B]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaExtraMemoryUsage, LEFT);
++line;
#endif
lcdDrawText(LCD_W/2, MENU_FOOTER_TOP+2, STR_MENUTORESET, CENTERED);
return true;
}
bool menuStatsAnalogs(event_t event)
{
MENU("Analogs", STATS_ICONS, menuTabStats, e_StatsAnalogs, 0, { 0 });
for (uint8_t i=0; i<NUM_ANALOGS; i++) {
coord_t y = MENU_CONTENT_TOP + (i/2)*FH;
coord_t x = MENUS_MARGIN_LEFT + (i & 1 ? LCD_W/2 : 0);
lcdDrawNumber(x, y, i+1, LEADING0|LEFT, 2, NULL, ":");
lcdDrawHexNumber(x+40, y, anaIn(i));
#if defined(JITTER_MEASURE)
lcdDrawNumber(x+100, y, rawJitter[i].get());
lcdDrawNumber(x+140, y, avgJitter[i].get());
lcdDrawNumber(x+180, y, (int16_t)calibratedAnalogs[CONVERT_MODE(i)]*250/256, PREC1);
#else
if (i < NUM_STICKS+NUM_POTS+NUM_SLIDERS)
lcdDrawNumber(x+100, y, (int16_t)calibratedAnalogs[CONVERT_MODE(i)]*25/256);
else if (i >= MOUSE1)
lcdDrawNumber(x+100, y, (int16_t)calibratedAnalogs[CALIBRATED_MOUSE1+i-MOUSE1]*25/256);
#endif
}
// SWR
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+7*FH, "RAS");
lcdDrawNumber(MENUS_MARGIN_LEFT+100, MENU_CONTENT_TOP+7*FH, telemetryData.swr.value);
return true;
}
#if defined(DEBUG_TRACE_BUFFER)
#define STATS_TRACES_INDEX_POS MENUS_MARGIN_LEFT
#define STATS_TRACES_TIME_POS MENUS_MARGIN_LEFT + 4*10
#define STATS_TRACES_EVENT_POS MENUS_MARGIN_LEFT + 14*10
#define STATS_TRACES_DATA_POS MENUS_MARGIN_LEFT + 20*10
bool menuStatsTraces(event_t event)
{
switch(event)
{
case EVT_KEY_LONG(KEY_ENTER):
dumpTraceBuffer();
killEvents(event);
break;
}
SIMPLE_MENU("", STATS_ICONS, menuTabStats, e_StatsTraces, TRACE_BUFFER_LEN);
uint8_t k = 0;
int8_t sub = menuVerticalPosition;
lcdDrawChar(STATS_TRACES_INDEX_POS, MENU_TITLE_TOP+2, '#', MENU_TITLE_COLOR);
lcdDrawText(STATS_TRACES_TIME_POS, MENU_TITLE_TOP+2, "Time", MENU_TITLE_COLOR);
lcdDrawText(STATS_TRACES_EVENT_POS, MENU_TITLE_TOP+2, "Event", MENU_TITLE_COLOR);
lcdDrawText(STATS_TRACES_DATA_POS, MENU_TITLE_TOP+2, "Data", MENU_TITLE_COLOR);
for (uint8_t i=0; i<NUM_BODY_LINES; i++) {
coord_t y = MENU_CONTENT_TOP + i * FH;
k = i+menuVerticalOffset;
// item
lcdDrawNumber(STATS_TRACES_INDEX_POS, y, k, LEFT | (sub==k ? INVERS : 0));
const struct TraceElement * te = getTraceElement(k);
if (te) {
// time
putstime_t tme = te->time % SECS_PER_DAY;
drawTimer(STATS_TRACES_TIME_POS, y, tme, TIMEHOUR|LEFT);
// event
lcdDrawNumber(STATS_TRACES_EVENT_POS, y, te->event, LEADING0|LEFT, 3);
// data
lcdDrawSizedText(STATS_TRACES_DATA_POS, y, "0x", 2);
lcdDrawHexNumber(lcdNextPos, y, (uint16_t)(te->data >> 16));
lcdDrawHexNumber(lcdNextPos, y, (uint16_t)(te->data & 0xFFFF));
}
}
return true;
}
#endif // defined(DEBUG_TRACE_BUFFER)

View file

@ -1,76 +1,76 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _HAPTIC_H_
#define _HAPTIC_H_
#define HAPTIC_QUEUE_LENGTH 4
class hapticQueue
{
public:
hapticQueue();
// only difference between these two functions is that one does the
// interupt queue (Now) and the other queues for playing ASAP.
void play(uint8_t tLen, uint8_t tPause, uint8_t tRepeat=0);
inline bool busy() { return (buzzTimeLeft > 0); }
void event(uint8_t e);
// heartbeat is responsibile for issueing the haptic buzzs and general square waves
// it is essentially the life of the class.
void heartbeat();
// bool freeslots(uint8_t slots);
inline bool empty() {
return (t_queueRidx == t_queueWidx);
}
protected:
inline uint8_t getHapticLength(uint8_t tLen) {
return ((g_eeGeneral.hapticLength * 2) + tLen) * 2;
}
private:
uint8_t t_queueRidx;
uint8_t t_queueWidx;
uint8_t buzzTimeLeft;
uint8_t buzzPause;
uint8_t hapticTick;
// queue arrays
uint8_t queueHapticLength[HAPTIC_QUEUE_LENGTH];
uint8_t queueHapticPause[HAPTIC_QUEUE_LENGTH];
uint8_t queueHapticRepeat[HAPTIC_QUEUE_LENGTH];
};
extern hapticQueue haptic;
#define IS_HAPTIC_BUSY() haptic.busy()
#define HAPTIC_HEARTBEAT() haptic.heartbeat()
#endif // _HAPTIC_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _HAPTIC_H_
#define _HAPTIC_H_
#define HAPTIC_QUEUE_LENGTH 4
class hapticQueue
{
public:
hapticQueue();
// only difference between these two functions is that one does the
// interupt queue (Now) and the other queues for playing ASAP.
void play(uint8_t tLen, uint8_t tPause, uint8_t tRepeat=0);
inline bool busy() { return (buzzTimeLeft > 0); }
void event(uint8_t e);
// heartbeat is responsibile for issueing the haptic buzzs and general square waves
// it is essentially the life of the class.
void heartbeat();
// bool freeslots(uint8_t slots);
inline bool empty() {
return (t_queueRidx == t_queueWidx);
}
protected:
inline uint8_t getHapticLength(uint8_t tLen) {
return ((g_eeGeneral.hapticLength * 2) + tLen) * 2;
}
private:
uint8_t t_queueRidx;
uint8_t t_queueWidx;
uint8_t buzzTimeLeft;
uint8_t buzzPause;
uint8_t hapticTick;
// queue arrays
uint8_t queueHapticLength[HAPTIC_QUEUE_LENGTH];
uint8_t queueHapticPause[HAPTIC_QUEUE_LENGTH];
uint8_t queueHapticRepeat[HAPTIC_QUEUE_LENGTH];
};
extern hapticQueue haptic;
#define IS_HAPTIC_BUSY() haptic.busy()
#define HAPTIC_HEARTBEAT() haptic.heartbeat()
#endif // _HAPTIC_H_

View file

@ -1,113 +1,113 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _KEYS_H_
#define _KEYS_H_
#define EVT_KEY_MASK(e) ((e) & 0x1f)
#if defined(PCBHORUS)
#define _MSK_KEY_BREAK 0x0200
#define _MSK_KEY_REPT 0x0400
#define _MSK_KEY_FIRST 0x0600
#define _MSK_KEY_LONG 0x0800
#define _MSK_KEY_FLAGS 0x0e00
#define EVT_ENTRY 0x1000
#define EVT_ENTRY_UP 0x2000
#else
#define _MSK_KEY_BREAK 0x20
#define _MSK_KEY_REPT 0x40
#define _MSK_KEY_FIRST 0x60
#define _MSK_KEY_LONG 0x80
#define _MSK_KEY_FLAGS 0xe0
#define EVT_ENTRY 0xbf
#define EVT_ENTRY_UP 0xbe
#endif
// normal order of events is: FIRST, LONG, REPEAT, REPEAT, ..., BREAK
#define EVT_KEY_FIRST(key) ((key)|_MSK_KEY_FIRST) // fired when key is pressed
#define EVT_KEY_LONG(key) ((key)|_MSK_KEY_LONG) // fired when key is held pressed for a while
#define EVT_KEY_REPT(key) ((key)|_MSK_KEY_REPT) // fired when key is held pressed long enough, fires multiple times with increasing speed
#define EVT_KEY_BREAK(key) ((key)|_MSK_KEY_BREAK) // fired when key is released (short or long), but only if the event was not killed
#define IS_KEY_FIRST(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_FIRST)
#define IS_KEY_LONG(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_LONG)
#define IS_KEY_REPT(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_REPT)
#define IS_KEY_BREAK(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_BREAK)
#if (defined(PCBHORUS) || defined(PCBFLAMENCO) || defined(PCBTARANIS)) && defined(ROTARY_ENCODER_NAVIGATION)
typedef uint16_t event_t;
#define EVT_ROTARY_BREAK EVT_KEY_BREAK(KEY_ENTER)
#define EVT_ROTARY_LONG EVT_KEY_LONG(KEY_ENTER)
#define EVT_ROTARY_LEFT 0xDF00
#define EVT_ROTARY_RIGHT 0xDE00
#define IS_NEXT_EVENT(event) (event==EVT_ROTARY_RIGHT)
#define IS_PREVIOUS_EVENT(event) (event==EVT_ROTARY_LEFT)
#elif defined(ROTARY_ENCODER_NAVIGATION)
typedef uint8_t event_t;
#define EVT_ROTARY_BREAK 0xcf
#define EVT_ROTARY_LONG 0xce
#define EVT_ROTARY_LEFT 0xdf
#define EVT_ROTARY_RIGHT 0xde
#define IS_NEXT_EVENT(event) (event==EVT_ROTARY_RIGHT || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN))
#define IS_PREVIOUS_EVENT(event) (event==EVT_ROTARY_LEFT || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP))
#else
typedef uint8_t event_t;
#define IS_NEXT_EVENT(event) (event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN))
#define IS_PREVIOUS_EVENT(event) (event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP))
#endif
#if defined(COLORLCD)
#define EVT_REFRESH 0xDD00
#endif
class Key
{
private:
uint8_t m_vals;
uint8_t m_cnt;
uint8_t m_state;
public:
void input(bool val);
bool state() const { return m_vals > 0; }
void pauseEvents();
void killEvents();
uint8_t key() const;
};
extern Key keys[NUM_KEYS];
extern event_t s_evt;
#define putEvent(evt) s_evt = evt
void pauseEvents(event_t event);
void killEvents(event_t event);
#if defined(CPUARM)
bool clearKeyEvents();
event_t getEvent(bool trim=false);
#else
void clearKeyEvents();
event_t getEvent();
#endif
uint8_t keyDown();
#endif // _KEYS_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _KEYS_H_
#define _KEYS_H_
#define EVT_KEY_MASK(e) ((e) & 0x1f)
#if defined(PCBHORUS)
#define _MSK_KEY_BREAK 0x0200
#define _MSK_KEY_REPT 0x0400
#define _MSK_KEY_FIRST 0x0600
#define _MSK_KEY_LONG 0x0800
#define _MSK_KEY_FLAGS 0x0e00
#define EVT_ENTRY 0x1000
#define EVT_ENTRY_UP 0x2000
#else
#define _MSK_KEY_BREAK 0x20
#define _MSK_KEY_REPT 0x40
#define _MSK_KEY_FIRST 0x60
#define _MSK_KEY_LONG 0x80
#define _MSK_KEY_FLAGS 0xe0
#define EVT_ENTRY 0xbf
#define EVT_ENTRY_UP 0xbe
#endif
// normal order of events is: FIRST, LONG, REPEAT, REPEAT, ..., BREAK
#define EVT_KEY_FIRST(key) ((key)|_MSK_KEY_FIRST) // fired when key is pressed
#define EVT_KEY_LONG(key) ((key)|_MSK_KEY_LONG) // fired when key is held pressed for a while
#define EVT_KEY_REPT(key) ((key)|_MSK_KEY_REPT) // fired when key is held pressed long enough, fires multiple times with increasing speed
#define EVT_KEY_BREAK(key) ((key)|_MSK_KEY_BREAK) // fired when key is released (short or long), but only if the event was not killed
#define IS_KEY_FIRST(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_FIRST)
#define IS_KEY_LONG(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_LONG)
#define IS_KEY_REPT(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_REPT)
#define IS_KEY_BREAK(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_BREAK)
#if (defined(PCBHORUS) || defined(PCBFLAMENCO) || defined(PCBTARANIS)) && defined(ROTARY_ENCODER_NAVIGATION)
typedef uint16_t event_t;
#define EVT_ROTARY_BREAK EVT_KEY_BREAK(KEY_ENTER)
#define EVT_ROTARY_LONG EVT_KEY_LONG(KEY_ENTER)
#define EVT_ROTARY_LEFT 0xDF00
#define EVT_ROTARY_RIGHT 0xDE00
#define IS_NEXT_EVENT(event) (event==EVT_ROTARY_RIGHT)
#define IS_PREVIOUS_EVENT(event) (event==EVT_ROTARY_LEFT)
#elif defined(ROTARY_ENCODER_NAVIGATION)
typedef uint8_t event_t;
#define EVT_ROTARY_BREAK 0xcf
#define EVT_ROTARY_LONG 0xce
#define EVT_ROTARY_LEFT 0xdf
#define EVT_ROTARY_RIGHT 0xde
#define IS_NEXT_EVENT(event) (event==EVT_ROTARY_RIGHT || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN))
#define IS_PREVIOUS_EVENT(event) (event==EVT_ROTARY_LEFT || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP))
#else
typedef uint8_t event_t;
#define IS_NEXT_EVENT(event) (event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN))
#define IS_PREVIOUS_EVENT(event) (event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP))
#endif
#if defined(COLORLCD)
#define EVT_REFRESH 0xDD00
#endif
class Key
{
private:
uint8_t m_vals;
uint8_t m_cnt;
uint8_t m_state;
public:
void input(bool val);
bool state() const { return m_vals > 0; }
void pauseEvents();
void killEvents();
uint8_t key() const;
};
extern Key keys[NUM_KEYS];
extern event_t s_evt;
#define putEvent(evt) s_evt = evt
void pauseEvents(event_t event);
void killEvents(event_t event);
#if defined(CPUARM)
bool clearKeyEvents();
event_t getEvent(bool trim=false);
#else
void clearKeyEvents();
event_t getEvent();
#endif
uint8_t keyDown();
#endif // _KEYS_H_

View file

@ -20,13 +20,13 @@
#ifndef _PWR_H_
#define _PWR_H_
enum PowerState {
e_power_on,
e_power_trainer,
e_power_usb,
e_power_off,
e_power_press,
};
enum PowerState {
e_power_on,
e_power_trainer,
e_power_usb,
e_power_off,
e_power_press,
};
#endif // _PWR_H_

View file

@ -1,63 +1,63 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _RTC_H_
#define _RTC_H_
#include <inttypes.h>
#define SECS_PER_HOUR 3600ul
#define SECS_PER_DAY 86400ul
#define TM_YEAR_BASE 1900
#define TIME_T_MIN (-LONG_MAX)
#define TIME_T_MAX (LONG_MAX)
typedef long int gtime_t;
struct gtm
{
int8_t tm_sec; /* Seconds. [0-60] (1 leap second) */
int8_t tm_min; /* Minutes. [0-59] */
int8_t tm_hour; /* Hours. [0-23] */
int8_t tm_mday; /* Day. [1-31] */
int8_t tm_mon; /* Month. [0-11] */
uint8_t tm_year; /* Year - 1900. Limited to the year 2155. */
int8_t tm_wday; /* Day of week. [0-6] */
int16_t tm_yday; /* Day of year. [0-365] Needed internally for calculations */
};
extern gtime_t g_rtcTime;
extern uint8_t g_ms100; // global to allow time set function to reset to zero
void rtcInit();
void rtcSetTime(const struct gtm * tm);
gtime_t gmktime (struct gtm *tm);
uint8_t rtcAdjust(uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec);
#if defined(__cplusplus) && !defined(SIMU)
extern "C" {
#endif
void gettime(struct gtm * tm);
#if defined(__cplusplus) && !defined(SIMU)
}
#endif
#endif // _RTC_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _RTC_H_
#define _RTC_H_
#include <inttypes.h>
#define SECS_PER_HOUR 3600ul
#define SECS_PER_DAY 86400ul
#define TM_YEAR_BASE 1900
#define TIME_T_MIN (-LONG_MAX)
#define TIME_T_MAX (LONG_MAX)
typedef long int gtime_t;
struct gtm
{
int8_t tm_sec; /* Seconds. [0-60] (1 leap second) */
int8_t tm_min; /* Minutes. [0-59] */
int8_t tm_hour; /* Hours. [0-23] */
int8_t tm_mday; /* Day. [1-31] */
int8_t tm_mon; /* Month. [0-11] */
uint8_t tm_year; /* Year - 1900. Limited to the year 2155. */
int8_t tm_wday; /* Day of week. [0-6] */
int16_t tm_yday; /* Day of year. [0-365] Needed internally for calculations */
};
extern gtime_t g_rtcTime;
extern uint8_t g_ms100; // global to allow time set function to reset to zero
void rtcInit();
void rtcSetTime(const struct gtm * tm);
gtime_t gmktime (struct gtm *tm);
uint8_t rtcAdjust(uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec);
#if defined(__cplusplus) && !defined(SIMU)
extern "C" {
#endif
void gettime(struct gtm * tm);
#if defined(__cplusplus) && !defined(SIMU)
}
#endif
#endif // _RTC_H_

View file

@ -20,20 +20,20 @@
#ifndef _SERIAL_H_
#define _SERIAL_H_
#ifdef __cplusplus
extern "C" {
#endif
void serialPutc(char c);
void serialPrintf(const char *format, ...);
void serialCrlf();
#ifdef __cplusplus
}
#endif
#define serialPrint(...) do { serialPrintf(__VA_ARGS__); serialCrlf(); } while(0)
#ifdef __cplusplus
extern "C" {
#endif
void serialPutc(char c);
void serialPrintf(const char *format, ...);
void serialCrlf();
#ifdef __cplusplus
}
#endif
#define serialPrint(...) do { serialPrintf(__VA_ARGS__); serialCrlf(); } while(0)
#endif // _SERIAL_H_

View file

@ -1,137 +1,137 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include "opentx.h"
#include "timers.h"
void eeLoadModel(uint8_t index)
{
if (index < MAX_MODELS) {
preModelLoad();
uint16_t size = eeLoadModelData(index);
#if defined(SIMU) && defined(EEPROM_ZONE_SIZE)
if (sizeof(uint16_t) + sizeof(g_model) > EEPROM_ZONE_SIZE) {
TRACE("Model data size can't exceed %d bytes (%d bytes)", int(EEPROM_ZONE_SIZE-sizeof(uint16_t)), (int)sizeof(g_model));
}
#endif
#if defined(SIMU)
if (size > 0 && size != sizeof(g_model)) {
TRACE("Model data read=%d bytes vs %d bytes\n", size, (int)sizeof(ModelData));
}
#endif
bool alarms = true;
if (size < EEPROM_MIN_MODEL_SIZE) { // if not loaded a fair amount
modelDefault(index) ;
storageCheck(true);
alarms = false;
}
postModelLoad(alarms);
}
}
uint8_t eeFindEmptyModel(uint8_t id, bool down)
{
uint8_t i = id;
for (;;) {
i = (MAX_MODELS + (down ? i+1 : i-1)) % MAX_MODELS;
if (!eeModelExists(i)) break;
if (i == id) return 0xff; // no free space in directory left
}
return i;
}
void selectModel(uint8_t sub)
{
#if !defined(COLORLCD)
showMessageBox(STR_LOADINGMODEL);
#endif
storageFlushCurrentModel();
storageCheck(true); // force writing of current model data before this is changed
g_eeGeneral.currModel = sub;
storageDirty(EE_GENERAL);
eeLoadModel(sub);
}
#if defined(CPUARM)
ModelHeader modelHeaders[MAX_MODELS];
void eeLoadModelHeaders()
{
for (uint32_t i=0; i<MAX_MODELS; i++) {
eeLoadModelHeader(i, &modelHeaders[i]);
}
}
#endif
void storageReadRadioSettings()
{
if (!eepromOpen() || !eeLoadGeneral()) {
storageEraseAll(true);
}
else {
eeLoadModelHeaders();
}
#if defined(CPUARM)
for (uint8_t i=0; languagePacks[i]!=NULL; i++) {
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
currentLanguagePackIdx = i;
currentLanguagePack = languagePacks[i];
}
}
#endif
}
void storageReadCurrentModel()
{
eeLoadModel(g_eeGeneral.currModel);
}
void storageReadAll()
{
storageReadRadioSettings();
storageReadCurrentModel();
}
void storageEraseAll(bool warn)
{
TRACE("storageEraseAll");
generalDefault();
modelDefault(0);
if (warn) {
ALERT(STR_STORAGE_WARNING, STR_BAD_RADIO_DATA, AU_BAD_RADIODATA);
}
RAISE_ALERT(STR_STORAGE_WARNING, STR_STORAGE_FORMAT, NULL, AU_NONE);
storageFormat();
storageDirty(EE_GENERAL|EE_MODEL);
storageCheck(true);
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include "opentx.h"
#include "timers.h"
void eeLoadModel(uint8_t index)
{
if (index < MAX_MODELS) {
preModelLoad();
uint16_t size = eeLoadModelData(index);
#if defined(SIMU) && defined(EEPROM_ZONE_SIZE)
if (sizeof(uint16_t) + sizeof(g_model) > EEPROM_ZONE_SIZE) {
TRACE("Model data size can't exceed %d bytes (%d bytes)", int(EEPROM_ZONE_SIZE-sizeof(uint16_t)), (int)sizeof(g_model));
}
#endif
#if defined(SIMU)
if (size > 0 && size != sizeof(g_model)) {
TRACE("Model data read=%d bytes vs %d bytes\n", size, (int)sizeof(ModelData));
}
#endif
bool alarms = true;
if (size < EEPROM_MIN_MODEL_SIZE) { // if not loaded a fair amount
modelDefault(index) ;
storageCheck(true);
alarms = false;
}
postModelLoad(alarms);
}
}
uint8_t eeFindEmptyModel(uint8_t id, bool down)
{
uint8_t i = id;
for (;;) {
i = (MAX_MODELS + (down ? i+1 : i-1)) % MAX_MODELS;
if (!eeModelExists(i)) break;
if (i == id) return 0xff; // no free space in directory left
}
return i;
}
void selectModel(uint8_t sub)
{
#if !defined(COLORLCD)
showMessageBox(STR_LOADINGMODEL);
#endif
storageFlushCurrentModel();
storageCheck(true); // force writing of current model data before this is changed
g_eeGeneral.currModel = sub;
storageDirty(EE_GENERAL);
eeLoadModel(sub);
}
#if defined(CPUARM)
ModelHeader modelHeaders[MAX_MODELS];
void eeLoadModelHeaders()
{
for (uint32_t i=0; i<MAX_MODELS; i++) {
eeLoadModelHeader(i, &modelHeaders[i]);
}
}
#endif
void storageReadRadioSettings()
{
if (!eepromOpen() || !eeLoadGeneral()) {
storageEraseAll(true);
}
else {
eeLoadModelHeaders();
}
#if defined(CPUARM)
for (uint8_t i=0; languagePacks[i]!=NULL; i++) {
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
currentLanguagePackIdx = i;
currentLanguagePack = languagePacks[i];
}
}
#endif
}
void storageReadCurrentModel()
{
eeLoadModel(g_eeGeneral.currModel);
}
void storageReadAll()
{
storageReadRadioSettings();
storageReadCurrentModel();
}
void storageEraseAll(bool warn)
{
TRACE("storageEraseAll");
generalDefault();
modelDefault(0);
if (warn) {
ALERT(STR_STORAGE_WARNING, STR_BAD_RADIO_DATA, AU_BAD_RADIODATA);
}
RAISE_ALERT(STR_STORAGE_WARNING, STR_STORAGE_FORMAT, NULL, AU_NONE);
storageFormat();
storageDirty(EE_GENERAL|EE_MODEL);
storageCheck(true);
}

View file

@ -18,25 +18,25 @@
* GNU General Public License for more details.
*/
#define EEPROM_MIN_MODEL_SIZE 256
uint16_t eeLoadModelData(uint8_t id);
uint16_t eeLoadGeneralSettingsData();
bool eeModelExists(uint8_t id);
void eeLoadModel(uint8_t id);
bool eeConvert();
void ConvertModel(int id, int version);
uint8_t eeFindEmptyModel(uint8_t id, bool down);
void selectModel(uint8_t sub);
#if defined(CPUARM)
extern ModelHeader modelHeaders[MAX_MODELS];
void eeLoadModelHeader(uint8_t id, ModelHeader *header);
void eeLoadModelHeaders();
#else
#define eeLoadModelHeaders()
#endif
#define EEPROM_MIN_MODEL_SIZE 256
uint16_t eeLoadModelData(uint8_t id);
uint16_t eeLoadGeneralSettingsData();
bool eeModelExists(uint8_t id);
void eeLoadModel(uint8_t id);
bool eeConvert();
void ConvertModel(int id, int version);
uint8_t eeFindEmptyModel(uint8_t id, bool down);
void selectModel(uint8_t sub);
#if defined(CPUARM)
extern ModelHeader modelHeaders[MAX_MODELS];
void eeLoadModelHeader(uint8_t id, ModelHeader *header);
void eeLoadModelHeaders();
#else
#define eeLoadModelHeaders()
#endif
void storageReadRadioSettings();
void storageReadCurrentModel();

File diff suppressed because it is too large Load diff

View file

@ -1,116 +1,116 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include "debug.h"
#undef errno
extern int errno;
extern int _end;
extern int _heap_end;
unsigned char * heap = (unsigned char *)&_end;
extern caddr_t _sbrk(int nbytes)
{
if (heap + nbytes < (unsigned char *)&_heap_end) {
unsigned char * prev_heap = heap;
heap += nbytes;
return (caddr_t)prev_heap;
}
else {
errno = ENOMEM;
return ((void *)-1);
}
}
#if !defined(SEMIHOSTING)
extern int _gettimeofday(void *p1, void *p2)
{
return 0;
}
extern int _link(char *old, char *nw)
{
return -1;
}
extern int _unlink(const char *path)
{
return -1;
}
extern int _open(const char *name, int flags, int mode)
{
return -1;
}
extern int _close(int file)
{
return -1;
}
extern int _fstat(int file, struct stat * st)
{
st->st_mode = S_IFCHR ;
return 0;
}
extern int _isatty(int file)
{
return 1;
}
extern int _lseek(int file, int ptr, int dir)
{
return 0;
}
extern int _read(int file, char *ptr, int len)
{
return 0;
}
extern int _write(int file, char *ptr, int len)
{
return 0;
}
extern void _exit(int status)
{
TRACE("_exit(%d)", status);
for (;;);
}
extern void _kill(int pid, int sig)
{
return ;
}
extern int _getpid()
{
return -1 ;
}
#endif
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include "debug.h"
#undef errno
extern int errno;
extern int _end;
extern int _heap_end;
unsigned char * heap = (unsigned char *)&_end;
extern caddr_t _sbrk(int nbytes)
{
if (heap + nbytes < (unsigned char *)&_heap_end) {
unsigned char * prev_heap = heap;
heap += nbytes;
return (caddr_t)prev_heap;
}
else {
errno = ENOMEM;
return ((void *)-1);
}
}
#if !defined(SEMIHOSTING)
extern int _gettimeofday(void *p1, void *p2)
{
return 0;
}
extern int _link(char *old, char *nw)
{
return -1;
}
extern int _unlink(const char *path)
{
return -1;
}
extern int _open(const char *name, int flags, int mode)
{
return -1;
}
extern int _close(int file)
{
return -1;
}
extern int _fstat(int file, struct stat * st)
{
st->st_mode = S_IFCHR ;
return 0;
}
extern int _isatty(int file)
{
return 1;
}
extern int _lseek(int file, int ptr, int dir)
{
return 0;
}
extern int _read(int file, char *ptr, int len)
{
return 0;
}
extern int _write(int file, char *ptr, int len)
{
return 0;
}
extern void _exit(int status)
{
TRACE("_exit(%d)", status);
for (;;);
}
extern void _kill(int pid, int sig)
{
return ;
}
extern int _getpid()
{
return -1 ;
}
#endif

View file

@ -1,364 +1,364 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#if defined(ROTARY_ENCODER_NAVIGATION)
#if defined(TELEMETREZ)
uint8_t TrotCount; // TeZ version
uint8_t LastTrotCount; // TeZ version
uint8_t RotEncoder;
#else
uint8_t RotPosition;
int8_t LastRotaryValue;
int8_t Rotary_diff;
int8_t RotaryControl;
uint8_t RotEncoder;
#endif
void rotencPoll()
{
#if defined(TELEMETREZ)
if (TrotCount != LastTrotCount) {
rotencValue[0] = LastTrotCount = TrotCount;
}
#else
// Rotary Encoder polling
PORTA = 0; // No pullups
DDRA = 0x1F; // Top 3 bits input
asm(" rjmp 1f");
asm("1:");
uint8_t rotary;
rotary = PINA;
DDRA = 0xFF; // Back to all outputs
rotary &= 0xE0;
RotEncoder = rotary; // just read the lcd pin
rotary &= 0xDF;
if ( rotary != RotPosition ) {
uint8_t x;
x = RotPosition & 0x40;
x <<= 1;
x ^= rotary & 0x80;
if ( x ) {
rotencValue[0] -= 1;
}
else {
rotencValue[0] += 1;
}
RotPosition = rotary;
}
#endif // TELEMETREZ
}
#else
#define ROTENC_DOWN() (0)
#endif // ROTARY_ENCODER_NAVIGATION
void boardInit()
{
#if !defined(SIMU)
// Set up I/O port data directions and initial states
DDRA = 0xff; PORTA = 0x00; // LCD data
DDRB = 0x81; PORTB = 0x7e; //pullups keys+nc
#if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
DDRC = 0xff; PORTC = 0x00;
#else
DDRC = 0x3e; PORTC = 0xc1; //pullups nc
#endif
DDRD = 0x00; PORTD = 0xff; //pullups keys
DDRE = (1<<OUT_E_BUZZER); PORTE = 0xff-(1<<OUT_E_BUZZER); //pullups + buzzer 0
DDRF = 0x00; PORTF = 0x00; //anain
DDRG = 0x14; PORTG = 0xfb; //pullups + SIM_CTL=1 = phonejack = ppm_in, Haptic output and off (0)
adcInit();
#if defined(CPUM2561)
TCCR2B = (0b111 << CS20); // Norm mode, clk/1024 (differs from ATmega64 chip)
OCR2A = 156;
TIMSK2 |= (1<<OCIE2A) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts
#else
// TCNT0 10ms = 16MHz/1024/156 periodic timer (9.984ms)
// (with 1:4 duty at 157 to average 10.0ms)
// Timer overflows at about 61Hz or once every 16ms.
TCCR0 = (0b111 << CS00); // Norm mode, clk/1024
OCR0 = 156;
#endif
#if defined(AUDIO) || defined(VOICE)
SET_TIMER_AUDIO_CTRL();
#if defined(CPUM2561)
OCR4A = 0xFF;
RESUME_AUDIO_INTERRUPT();
#else
TIMSK |= (1<<OCIE0) | (1<<TOIE0) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts
#endif
#elif defined(PWM_BACKLIGHT)
/** Smartieparts LED Backlight is connected to PORTB/pin7, which can be used as pwm output of timer2 **/
#if defined(CPUM2561)
#if defined(SP22)
TCCR0A = (1<<WGM00)|(1<<COM0A1)|(1<<COM0A0); // inv. pwm mode, clk/64
#else
TCCR0A = (1<<WGM00)|(1<<COM0A1); // pwm mode, clk/64
#endif
TCCR0B = (0b011<<CS00);
#else
#if defined(SP22)
TCCR2 = (0b011<<CS20)|(1<<WGM20)|(1<<COM21)|(1<<COM20); // inv. pwm mode, clk/64
#else
TCCR2 = (0b011<<CS20)|(1<<WGM20)|(1<<COM21); // pwm mode, clk/64
#endif
TIMSK |= (1<<OCIE0) | (1<<TOIE0); // Enable Output-Compare and Overflow interrrupts
#endif
#else
#if !defined(CPUM2561)
TIMSK |= (1<<OCIE0) | (1<<TOIE0); // Enable Output-Compare and Overflow interrrupts
#endif
#endif
#endif // !defined(SIMU)
}
#if !defined(SIMU) && (defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED))
uint8_t pf7_digital[MUX_PF7_DIGITAL_MAX - MUX_PF7_DIGITAL_MIN + 1];
/**
* Update ADC PF7 using 14051 multiplexer
* X0 : Battery voltage
* X1 : AIL SW
* X2 : THR SW
* X3 : TRIM LEFT VERTICAL UP
* X4 : TRIM LEFT VERTICAL DOWN
*/
void processMultiplexAna()
{
static uint8_t muxNum = MUX_BATT;
uint8_t nextMuxNum = muxNum-1;
switch (muxNum) {
case MUX_BATT:
s_anaFilt[TX_VOLTAGE] = s_anaFilt[X14051];
nextMuxNum = MUX_MAX;
break;
case MUX_AIL:
case MUX_THR:
case MUX_TRM_LV_UP:
case MUX_TRM_LV_DWN:
// Digital switch depend from input voltage
// take half voltage to determine digital state
pf7_digital[muxNum - MUX_PF7_DIGITAL_MIN] = (s_anaFilt[X14051] >= (s_anaFilt[TX_VOLTAGE] / 2)) ? 1 : 0;
break;
}
// set the mux number for the next ADC convert,
// stabilize voltage before ADC read.
muxNum = nextMuxNum;
PORTC &= ~((1 << PC7) | (1 << PC6) | (1 << PC0));
if(muxNum & 1) PORTC |= (1 << PC7); // Mux CTRL A
if(muxNum & 2) PORTC |= (1 << PC6); // Mux CTRL B
if(muxNum & 4) PORTC |= (1 << PC0); // Mux CTRL C
}
#endif
#if !defined(SIMU) && (defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED))
#define THR_STATE() pf7_digital[PF7_THR]
#define AIL_STATE() pf7_digital[PF7_AIL]
#elif defined(TELEMETRY_JETI) || defined(TELEMETRY_FRSKY) || defined(TELEMETRY_ARDUPILOT) || defined(TELEMETRY_NMEA) || defined(TELEMETRY_MAVLINK)
#define THR_STATE() (PINC & (1<<INP_C_ThrCt))
#define AIL_STATE() (PINC & (1<<INP_C_AileDR))
#else
#define THR_STATE() (PINE & (1<<INP_E_ThrCt))
#define AIL_STATE() (PINE & (1<<INP_E_AileDR))
#endif
uint8_t keyState(uint8_t index)
{
return keys[index].state();
}
uint8_t switchState(uint8_t index)
{
uint8_t result = 0;
switch (index) {
case SW_ELE:
result = PINE & (1<<INP_E_ElevDR);
break;
case SW_AIL:
result = AIL_STATE();
break;
case SW_RUD:
result = PING & (1<<INP_G_RuddDR);
break;
// INP_G_ID1 INP_E_ID2
// id0 0 1
// id1 1 1
// id2 1 0
case SW_ID0:
result = !(PING & (1<<INP_G_ID1));
break;
case SW_ID1:
result = (PING & (1<<INP_G_ID1)) && (PINE & (1<<INP_E_ID2));
break;
case SW_ID2:
result = !(PINE & (1<<INP_E_ID2));
break;
case SW_GEA:
result = PINE & (1<<INP_E_Gear);
break;
case SW_THR:
result = THR_STATE();
break;
case SW_TRN:
result = PINE & (1<<INP_E_Trainer);
break;
default:
break;
}
return result;
}
// Trim switches ...
uint8_t trimHelper(uint8_t negpin, uint8_t idx)
{
switch(idx){
case 0: return negpin & TRIMS_GPIO_PIN_LHL;
case 1: return negpin & TRIMS_GPIO_PIN_LHR;
#if !defined(SIMU) && defined(TELEMETRY_MOD_14051_SWAPPED)
case 2: return !pf7_digital[PF7_TRM_LV_DWN];
case 3: return !pf7_digital[PF7_TRM_LV_UP];
#else
case 2: return negpin & TRIMS_GPIO_PIN_LVD;
case 3: return negpin & TRIMS_GPIO_PIN_LVU;
#endif
case 4: return negpin & TRIMS_GPIO_PIN_RVD;
case 5: return negpin & TRIMS_GPIO_PIN_RVU;
case 6: return negpin & TRIMS_GPIO_PIN_RHL;
case 7: return negpin & TRIMS_GPIO_PIN_RHR;
default: return 0;
}
}
uint8_t trimDown(uint8_t idx)
{
return trimHelper(~PIND, idx);
}
void readKeysAndTrims()
{
uint8_t index = KEY_MENU;
// User buttons ...
uint8_t in = ~PINB;
for (int i=1; i<7; i++) {
keys[index].input(in & (1<<i));
++index;
}
// Trims ...
in = ~PIND;
for (int i=0; i<8; i++) {
// INP_D_TRM_RH_UP 0 .. INP_D_TRM_LH_UP 7
keys[index].input(trimHelper(in, i));
++index;
}
#if defined(ROTARY_ENCODER_NAVIGATION)
keys[index].input(ROTENC_DOWN()); // Rotary Enc. Switch
#endif
#if defined(NAVIGATION_STICKS)
if (~PINB & 0x7E) {
StickScrollTimer = STICK_SCROLL_TIMEOUT;
}
#endif
}
bool checkSlaveMode()
{
// no power -> only phone jack = slave mode
static bool lastSlaveMode = false;
static uint8_t checkDelay = 0;
if (IS_AUDIO_BUSY()) {
checkDelay = 20;
}
else if (checkDelay) {
--checkDelay;
}
else {
lastSlaveMode = (PING & (1<<INP_G_RF_POW));
}
return lastSlaveMode;
}
#if defined(PWM_BACKLIGHT)
// exponential PWM table for linear brightness
static const uint8_t pwmtable[16] PROGMEM =
{
0, 2, 3, 4, 6, 8, 11, 16, 23, 32, 45, 64, 90, 128, 181, 255
};
static uint8_t bl_target;
static uint8_t bl_current;
void backlightEnable()
{
bl_target = 15 - g_eeGeneral.blOnBright;
}
void backlightDisable()
{
bl_target = g_eeGeneral.blOffBright;
}
bool isBacklightEnabled()
{
return (bl_target==g_eeGeneral.blOnBright);
}
void backlightFade() // called from per10ms()
{
if (bl_target != bl_current) {
#if defined(CPUM2561)
if (bl_target > bl_current)
OCR0A = pgm_read_byte(&pwmtable[++bl_current]);
else
OCR0A = pgm_read_byte(&pwmtable[--bl_current]);
#else
if (bl_target > bl_current)
OCR2 = pgm_read_byte(&pwmtable[++bl_current]);
else
OCR2 = pgm_read_byte(&pwmtable[--bl_current]);
#endif
}
}
#endif
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#if defined(ROTARY_ENCODER_NAVIGATION)
#if defined(TELEMETREZ)
uint8_t TrotCount; // TeZ version
uint8_t LastTrotCount; // TeZ version
uint8_t RotEncoder;
#else
uint8_t RotPosition;
int8_t LastRotaryValue;
int8_t Rotary_diff;
int8_t RotaryControl;
uint8_t RotEncoder;
#endif
void rotencPoll()
{
#if defined(TELEMETREZ)
if (TrotCount != LastTrotCount) {
rotencValue[0] = LastTrotCount = TrotCount;
}
#else
// Rotary Encoder polling
PORTA = 0; // No pullups
DDRA = 0x1F; // Top 3 bits input
asm(" rjmp 1f");
asm("1:");
uint8_t rotary;
rotary = PINA;
DDRA = 0xFF; // Back to all outputs
rotary &= 0xE0;
RotEncoder = rotary; // just read the lcd pin
rotary &= 0xDF;
if ( rotary != RotPosition ) {
uint8_t x;
x = RotPosition & 0x40;
x <<= 1;
x ^= rotary & 0x80;
if ( x ) {
rotencValue[0] -= 1;
}
else {
rotencValue[0] += 1;
}
RotPosition = rotary;
}
#endif // TELEMETREZ
}
#else
#define ROTENC_DOWN() (0)
#endif // ROTARY_ENCODER_NAVIGATION
void boardInit()
{
#if !defined(SIMU)
// Set up I/O port data directions and initial states
DDRA = 0xff; PORTA = 0x00; // LCD data
DDRB = 0x81; PORTB = 0x7e; //pullups keys+nc
#if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
DDRC = 0xff; PORTC = 0x00;
#else
DDRC = 0x3e; PORTC = 0xc1; //pullups nc
#endif
DDRD = 0x00; PORTD = 0xff; //pullups keys
DDRE = (1<<OUT_E_BUZZER); PORTE = 0xff-(1<<OUT_E_BUZZER); //pullups + buzzer 0
DDRF = 0x00; PORTF = 0x00; //anain
DDRG = 0x14; PORTG = 0xfb; //pullups + SIM_CTL=1 = phonejack = ppm_in, Haptic output and off (0)
adcInit();
#if defined(CPUM2561)
TCCR2B = (0b111 << CS20); // Norm mode, clk/1024 (differs from ATmega64 chip)
OCR2A = 156;
TIMSK2 |= (1<<OCIE2A) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts
#else
// TCNT0 10ms = 16MHz/1024/156 periodic timer (9.984ms)
// (with 1:4 duty at 157 to average 10.0ms)
// Timer overflows at about 61Hz or once every 16ms.
TCCR0 = (0b111 << CS00); // Norm mode, clk/1024
OCR0 = 156;
#endif
#if defined(AUDIO) || defined(VOICE)
SET_TIMER_AUDIO_CTRL();
#if defined(CPUM2561)
OCR4A = 0xFF;
RESUME_AUDIO_INTERRUPT();
#else
TIMSK |= (1<<OCIE0) | (1<<TOIE0) | (1<<TOIE2); // Enable Output-Compare and Overflow interrrupts
#endif
#elif defined(PWM_BACKLIGHT)
/** Smartieparts LED Backlight is connected to PORTB/pin7, which can be used as pwm output of timer2 **/
#if defined(CPUM2561)
#if defined(SP22)
TCCR0A = (1<<WGM00)|(1<<COM0A1)|(1<<COM0A0); // inv. pwm mode, clk/64
#else
TCCR0A = (1<<WGM00)|(1<<COM0A1); // pwm mode, clk/64
#endif
TCCR0B = (0b011<<CS00);
#else
#if defined(SP22)
TCCR2 = (0b011<<CS20)|(1<<WGM20)|(1<<COM21)|(1<<COM20); // inv. pwm mode, clk/64
#else
TCCR2 = (0b011<<CS20)|(1<<WGM20)|(1<<COM21); // pwm mode, clk/64
#endif
TIMSK |= (1<<OCIE0) | (1<<TOIE0); // Enable Output-Compare and Overflow interrrupts
#endif
#else
#if !defined(CPUM2561)
TIMSK |= (1<<OCIE0) | (1<<TOIE0); // Enable Output-Compare and Overflow interrrupts
#endif
#endif
#endif // !defined(SIMU)
}
#if !defined(SIMU) && (defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED))
uint8_t pf7_digital[MUX_PF7_DIGITAL_MAX - MUX_PF7_DIGITAL_MIN + 1];
/**
* Update ADC PF7 using 14051 multiplexer
* X0 : Battery voltage
* X1 : AIL SW
* X2 : THR SW
* X3 : TRIM LEFT VERTICAL UP
* X4 : TRIM LEFT VERTICAL DOWN
*/
void processMultiplexAna()
{
static uint8_t muxNum = MUX_BATT;
uint8_t nextMuxNum = muxNum-1;
switch (muxNum) {
case MUX_BATT:
s_anaFilt[TX_VOLTAGE] = s_anaFilt[X14051];
nextMuxNum = MUX_MAX;
break;
case MUX_AIL:
case MUX_THR:
case MUX_TRM_LV_UP:
case MUX_TRM_LV_DWN:
// Digital switch depend from input voltage
// take half voltage to determine digital state
pf7_digital[muxNum - MUX_PF7_DIGITAL_MIN] = (s_anaFilt[X14051] >= (s_anaFilt[TX_VOLTAGE] / 2)) ? 1 : 0;
break;
}
// set the mux number for the next ADC convert,
// stabilize voltage before ADC read.
muxNum = nextMuxNum;
PORTC &= ~((1 << PC7) | (1 << PC6) | (1 << PC0));
if(muxNum & 1) PORTC |= (1 << PC7); // Mux CTRL A
if(muxNum & 2) PORTC |= (1 << PC6); // Mux CTRL B
if(muxNum & 4) PORTC |= (1 << PC0); // Mux CTRL C
}
#endif
#if !defined(SIMU) && (defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED))
#define THR_STATE() pf7_digital[PF7_THR]
#define AIL_STATE() pf7_digital[PF7_AIL]
#elif defined(TELEMETRY_JETI) || defined(TELEMETRY_FRSKY) || defined(TELEMETRY_ARDUPILOT) || defined(TELEMETRY_NMEA) || defined(TELEMETRY_MAVLINK)
#define THR_STATE() (PINC & (1<<INP_C_ThrCt))
#define AIL_STATE() (PINC & (1<<INP_C_AileDR))
#else
#define THR_STATE() (PINE & (1<<INP_E_ThrCt))
#define AIL_STATE() (PINE & (1<<INP_E_AileDR))
#endif
uint8_t keyState(uint8_t index)
{
return keys[index].state();
}
uint8_t switchState(uint8_t index)
{
uint8_t result = 0;
switch (index) {
case SW_ELE:
result = PINE & (1<<INP_E_ElevDR);
break;
case SW_AIL:
result = AIL_STATE();
break;
case SW_RUD:
result = PING & (1<<INP_G_RuddDR);
break;
// INP_G_ID1 INP_E_ID2
// id0 0 1
// id1 1 1
// id2 1 0
case SW_ID0:
result = !(PING & (1<<INP_G_ID1));
break;
case SW_ID1:
result = (PING & (1<<INP_G_ID1)) && (PINE & (1<<INP_E_ID2));
break;
case SW_ID2:
result = !(PINE & (1<<INP_E_ID2));
break;
case SW_GEA:
result = PINE & (1<<INP_E_Gear);
break;
case SW_THR:
result = THR_STATE();
break;
case SW_TRN:
result = PINE & (1<<INP_E_Trainer);
break;
default:
break;
}
return result;
}
// Trim switches ...
uint8_t trimHelper(uint8_t negpin, uint8_t idx)
{
switch(idx){
case 0: return negpin & TRIMS_GPIO_PIN_LHL;
case 1: return negpin & TRIMS_GPIO_PIN_LHR;
#if !defined(SIMU) && defined(TELEMETRY_MOD_14051_SWAPPED)
case 2: return !pf7_digital[PF7_TRM_LV_DWN];
case 3: return !pf7_digital[PF7_TRM_LV_UP];
#else
case 2: return negpin & TRIMS_GPIO_PIN_LVD;
case 3: return negpin & TRIMS_GPIO_PIN_LVU;
#endif
case 4: return negpin & TRIMS_GPIO_PIN_RVD;
case 5: return negpin & TRIMS_GPIO_PIN_RVU;
case 6: return negpin & TRIMS_GPIO_PIN_RHL;
case 7: return negpin & TRIMS_GPIO_PIN_RHR;
default: return 0;
}
}
uint8_t trimDown(uint8_t idx)
{
return trimHelper(~PIND, idx);
}
void readKeysAndTrims()
{
uint8_t index = KEY_MENU;
// User buttons ...
uint8_t in = ~PINB;
for (int i=1; i<7; i++) {
keys[index].input(in & (1<<i));
++index;
}
// Trims ...
in = ~PIND;
for (int i=0; i<8; i++) {
// INP_D_TRM_RH_UP 0 .. INP_D_TRM_LH_UP 7
keys[index].input(trimHelper(in, i));
++index;
}
#if defined(ROTARY_ENCODER_NAVIGATION)
keys[index].input(ROTENC_DOWN()); // Rotary Enc. Switch
#endif
#if defined(NAVIGATION_STICKS)
if (~PINB & 0x7E) {
StickScrollTimer = STICK_SCROLL_TIMEOUT;
}
#endif
}
bool checkSlaveMode()
{
// no power -> only phone jack = slave mode
static bool lastSlaveMode = false;
static uint8_t checkDelay = 0;
if (IS_AUDIO_BUSY()) {
checkDelay = 20;
}
else if (checkDelay) {
--checkDelay;
}
else {
lastSlaveMode = (PING & (1<<INP_G_RF_POW));
}
return lastSlaveMode;
}
#if defined(PWM_BACKLIGHT)
// exponential PWM table for linear brightness
static const uint8_t pwmtable[16] PROGMEM =
{
0, 2, 3, 4, 6, 8, 11, 16, 23, 32, 45, 64, 90, 128, 181, 255
};
static uint8_t bl_target;
static uint8_t bl_current;
void backlightEnable()
{
bl_target = 15 - g_eeGeneral.blOnBright;
}
void backlightDisable()
{
bl_target = g_eeGeneral.blOffBright;
}
bool isBacklightEnabled()
{
return (bl_target==g_eeGeneral.blOnBright);
}
void backlightFade() // called from per10ms()
{
if (bl_target != bl_current) {
#if defined(CPUM2561)
if (bl_target > bl_current)
OCR0A = pgm_read_byte(&pwmtable[++bl_current]);
else
OCR0A = pgm_read_byte(&pwmtable[--bl_current]);
#else
if (bl_target > bl_current)
OCR2 = pgm_read_byte(&pwmtable[++bl_current]);
else
OCR2 = pgm_read_byte(&pwmtable[--bl_current]);
#endif
}
}
#endif

View file

@ -1,260 +1,260 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BOARD_STOCK_H_
#define _BOARD_STOCK_H_
#include "../common/avr/board_avr.h"
//
// elev thr
// LV RV
// 2 ^ 4 ^
// 1 2
// | rudd | aile
// <----X--3-> LH <----X--0-> RH
// 6 | 7 1 | 0
// | |
// 3 v 5 v
//
//PORTA 7 6 5 4 3 2 1 0
// O O O O O O O O
// ------------------------ LCD_DAT -----------------------
//
//PORTB 7 6 5 4 3 2 1 0
// O i i i i i i O
// light KEY_LFT KEY_RGT KEY_UP KEY_DWN KEY_EXT KEY_MEN PPM
//
//PORTC 7 6 5 4 3 2 1 0
// - - O O O O O -
// NC NC LCD_E LCD_RNW LCD_A0 LCD_RES LCD_CS1 NC
//
//PORTD 7 6 5 4 3 2 1 0
// i i i i i i i i
// TRM_D_DWN _UP TRM_C_DWN _UP TRM_B_DWN _UP TRM_A_DWN _UP
//
//PORTE 7 6 5 4 3 2 1 0
// i i i i O i i i
// PPM_IN ID2 Trainer Gear Buzzer ElevDR AileDR THRCT
//
//PORTF 7 6 5 4 3 2 1 0
// ai ai ai ai ai ai ai ai
// ANA_ BAT PITT_TRM HOV_THR HOV_PIT STCK_LH STCK_RV STCK_LV STCK_RH
// rud thro elev aile
//PORTG 7 6 5 4 3 2 1 0
// - - - O i i i
// SIM_CTL ID1 Haptic RF_POW RuddDR
// Board driver
void boardInit(void);
#define boardOff() pwrOff()
// Keys
#define KEYS_GPIO_REG_MENU pinb
#define KEYS_GPIO_PIN_MENU (1<<1)
#define KEYS_GPIO_REG_EXIT pinb
#define KEYS_GPIO_PIN_EXIT (1<<2)
#define KEYS_GPIO_REG_RIGHT pinb
#define KEYS_GPIO_PIN_RIGHT (1<<5)
#define KEYS_GPIO_REG_LEFT pinb
#define KEYS_GPIO_PIN_LEFT (1<<6)
#define KEYS_GPIO_REG_UP pinb
#define KEYS_GPIO_PIN_UP (1<<4)
#define KEYS_GPIO_REG_DOWN pinb
#define KEYS_GPIO_PIN_DOWN (1<<3)
// Trims
#define TRIMS_GPIO_REG_LHL pind
#define TRIMS_GPIO_PIN_LHL (1<<6)
#define TRIMS_GPIO_REG_LVD pind
#define TRIMS_GPIO_PIN_LVD (1<<3)
#define TRIMS_GPIO_REG_RVU pind
#define TRIMS_GPIO_PIN_RVU (1<<4)
#define TRIMS_GPIO_REG_RHL pind
#define TRIMS_GPIO_PIN_RHL (1<<1)
#define TRIMS_GPIO_REG_LHR pind
#define TRIMS_GPIO_PIN_LHR (1<<7)
#define TRIMS_GPIO_REG_LVU pind
#define TRIMS_GPIO_PIN_LVU (1<<2)
#define TRIMS_GPIO_REG_RVD pind
#define TRIMS_GPIO_PIN_RVD (1<<5)
#define TRIMS_GPIO_REG_RHR pind
#define TRIMS_GPIO_PIN_RHR (1<<0)
#if defined(CPUM2561)
#define TIMER_16KHZ_VECT TIMER2_OVF_vect
#define COUNTER_16KHZ TCNT2
#define TIMER_10MS_VECT TIMER2_COMPA_vect
#define TIMER_10MS_COMPVAL OCR2A
#define PAUSE_10MS_INTERRUPT() TIMSK2 &= ~(1<<OCIE2A)
#define RESUME_10MS_INTERRUPT() TIMSK2 |= (1<<OCIE2A)
#define PAUSE_PPMIN_INTERRUPT() TIMSK3 &= ~(1<<ICIE3)
#define RESUME_PPMIN_INTERRUPT() TIMSK3 |= (1<<ICIE3)
#define TIMER_AUDIO_VECT TIMER4_COMPA_vect
#define SET_TIMER_AUDIO_CTRL() TCCR4B = (1 << WGM42) | (0b010 << CS40)
#define PAUSE_AUDIO_INTERRUPT() TIMSK4 &= ~(1<<OCIE4A)
#define RESUME_AUDIO_INTERRUPT() TIMSK4 |= (1<<OCIE4A)
#else
#define TIMER_16KHZ_VECT TIMER0_OVF_vect
#define COUNTER_16KHZ TCNT0
#define TIMER_10MS_VECT TIMER0_COMP_vect
#define TIMER_10MS_COMPVAL OCR0
#define PAUSE_10MS_INTERRUPT() TIMSK &= ~(1<<OCIE0)
#define RESUME_10MS_INTERRUPT() TIMSK |= (1<<OCIE0)
#define PAUSE_PPMIN_INTERRUPT() ETIMSK &= ~(1<<TICIE3)
#define RESUME_PPMIN_INTERRUPT() ETIMSK |= (1<<TICIE3)
#define TIMER_AUDIO_VECT TIMER2_OVF_vect
#define SET_TIMER_AUDIO_CTRL() TCCR2 = (0b010 << CS00) // Norm mode, clk/8
#define PAUSE_AUDIO_INTERRUPT() TIMSK &= ~(1<<TOIE2)
#define RESUME_AUDIO_INTERRUPT() TIMSK |= (1<<TOIE2)
#endif
// Power driver (none)
#define pwrCheck() (e_power_on)
#define pwrOff()
#define UNEXPECTED_SHUTDOWN() (mcusr & (1 << WDRF))
// Trainer driver
bool checkSlaveMode();
#define OUT_G_SIM_CTL 4 // 1 : phone-jack=ppm_in
#define SLAVE_MODE() checkSlaveMode()
#define JACK_PPM_OUT() PORTG &= ~(1<<OUT_G_SIM_CTL)
#define JACK_PPM_IN() PORTG |= (1<<OUT_G_SIM_CTL)
// Backlight driver
#define OUT_B_LIGHT 7
#if defined(PWM_BACKLIGHT)
void backlightEnable();
void backlightDisable();
bool isBacklightEnabled();
void backlightFade();
#elif defined(SP22)
#define backlightEnable() PORTB &= ~(1<<OUT_B_LIGHT)
#define backlightDisable() PORTB |= (1<<OUT_B_LIGHT)
#define isBacklightEnabled() (~PORTB & (1<<OUT_B_LIGHT))
#else
#define backlightEnable() PORTB |= (1<<OUT_B_LIGHT)
#define backlightDisable() PORTB &= ~(1<<OUT_B_LIGHT)
#define isBacklightEnabled() (PORTB & (1<<OUT_B_LIGHT))
#endif
#if defined(VOICE) && !defined(SIMU)
#define BACKLIGHT_ENABLE() Voice.Backlight = 1
#define BACKLIGHT_DISABLE() Voice.Backlight = 0
#else
#define BACKLIGHT_ENABLE() backlightEnable()
#define BACKLIGHT_DISABLE() backlightDisable()
#endif
#define OUT_B_PPM 0
#define INP_E_PPM_IN 7
#define INP_E_ID2 6
#define INP_E_Trainer 5
#define INP_E_Gear 4
#define OUT_E_BUZZER 3
#define INP_E_ElevDR 2
#if defined(TELEMETRY_JETI) || defined(TELEMETRY_FRSKY) || defined(TELEMETRY_ARDUPILOT) || defined(TELEMETRY_NMEA) || defined(TELEMETRY_MAVLINK)
#define INP_C_ThrCt 6
#define INP_C_AileDR 7
#else
#define INP_E_ThrCt 0
#define INP_E_AileDR 1
#endif
#define INP_G_ID1 3
#define OUT_G_HAPTIC 2
#define INP_G_RF_POW 1
#define INP_G_RuddDR 0
// Rotary Encoder driver
#if defined(ROTARY_ENCODER_NAVIGATION)
extern uint8_t RotEncoder;
#if defined(TELEMETREZ)
#define ROTENC_DOWN() (RotEncoder != 0)
#else
#define ROTENC_DOWN() (RotEncoder & 0x20)
#endif
#else
#define ROTENC_DOWN() (0)
#endif
// Keys driver
inline uint8_t keyDown()
{
return ((~PINB) & 0x7E) | ROTENC_DOWN();
}
#if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
enum MuxInput {
MUX_BATT,
MUX_AIL,
MUX_PF7_DIGITAL_MIN = MUX_AIL,
MUX_THR,
MUX_TRM_LV_UP,
MUX_TRM_LV_DWN,
MUX_PF7_DIGITAL_MAX = MUX_TRM_LV_DWN,
MUX_MAX = MUX_PF7_DIGITAL_MAX
};
enum Pf7Digital {
PF7_AIL = MUX_AIL - MUX_PF7_DIGITAL_MIN,
PF7_THR = MUX_THR - MUX_PF7_DIGITAL_MIN,
PF7_TRM_LV_UP = MUX_TRM_LV_UP - MUX_PF7_DIGITAL_MIN,
PF7_TRM_LV_DWN = MUX_TRM_LV_DWN - MUX_PF7_DIGITAL_MIN,
};
extern uint8_t pf7_digital[MUX_PF7_DIGITAL_MAX - MUX_PF7_DIGITAL_MIN + 1];
void processMultiplexAna();
#endif
#if defined(TELEMETRY_MOD_14051_SWAPPED)
#define TRIMS_PRESSED() (~PIND & ~0x0c || pf7_digital[PF7_TRM_LV_UP] || pf7_digital[PF7_TRM_LV_DWN])
#else
#define TRIMS_PRESSED() (~PIND)
#endif
#define KEYS_PRESSED() (~PINB)
// LCD driver
#define PORTA_LCD_DAT PORTA
#define PORTC_LCD_CTRL PORTC
#define OUT_C_LCD_E 5
#define OUT_C_LCD_RnW 4
#define OUT_C_LCD_A0 3
#define OUT_C_LCD_RES 2
#define OUT_C_LCD_CS1 1
// Rotary encoder driver
#if defined(ROTARY_ENCODER_NAVIGATION)
extern uint8_t RotEncoder ;
void rotencPoll();
#endif
// Haptic
#define hapticOn() PORTG |= (1 << OUT_G_HAPTIC)
#define hapticOff() PORTG &= ~(1 << OUT_G_HAPTIC)
// USB fake driver
#define usbPlugged() false
// Buzzer driver
#define buzzerOn() PORTE |= (1 << OUT_E_BUZZER)
#define buzzerOff() PORTE &= ~(1 << OUT_E_BUZZER)
#endif // _BOARD_STOCK_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BOARD_STOCK_H_
#define _BOARD_STOCK_H_
#include "../common/avr/board_avr.h"
//
// elev thr
// LV RV
// 2 ^ 4 ^
// 1 2
// | rudd | aile
// <----X--3-> LH <----X--0-> RH
// 6 | 7 1 | 0
// | |
// 3 v 5 v
//
//PORTA 7 6 5 4 3 2 1 0
// O O O O O O O O
// ------------------------ LCD_DAT -----------------------
//
//PORTB 7 6 5 4 3 2 1 0
// O i i i i i i O
// light KEY_LFT KEY_RGT KEY_UP KEY_DWN KEY_EXT KEY_MEN PPM
//
//PORTC 7 6 5 4 3 2 1 0
// - - O O O O O -
// NC NC LCD_E LCD_RNW LCD_A0 LCD_RES LCD_CS1 NC
//
//PORTD 7 6 5 4 3 2 1 0
// i i i i i i i i
// TRM_D_DWN _UP TRM_C_DWN _UP TRM_B_DWN _UP TRM_A_DWN _UP
//
//PORTE 7 6 5 4 3 2 1 0
// i i i i O i i i
// PPM_IN ID2 Trainer Gear Buzzer ElevDR AileDR THRCT
//
//PORTF 7 6 5 4 3 2 1 0
// ai ai ai ai ai ai ai ai
// ANA_ BAT PITT_TRM HOV_THR HOV_PIT STCK_LH STCK_RV STCK_LV STCK_RH
// rud thro elev aile
//PORTG 7 6 5 4 3 2 1 0
// - - - O i i i
// SIM_CTL ID1 Haptic RF_POW RuddDR
// Board driver
void boardInit(void);
#define boardOff() pwrOff()
// Keys
#define KEYS_GPIO_REG_MENU pinb
#define KEYS_GPIO_PIN_MENU (1<<1)
#define KEYS_GPIO_REG_EXIT pinb
#define KEYS_GPIO_PIN_EXIT (1<<2)
#define KEYS_GPIO_REG_RIGHT pinb
#define KEYS_GPIO_PIN_RIGHT (1<<5)
#define KEYS_GPIO_REG_LEFT pinb
#define KEYS_GPIO_PIN_LEFT (1<<6)
#define KEYS_GPIO_REG_UP pinb
#define KEYS_GPIO_PIN_UP (1<<4)
#define KEYS_GPIO_REG_DOWN pinb
#define KEYS_GPIO_PIN_DOWN (1<<3)
// Trims
#define TRIMS_GPIO_REG_LHL pind
#define TRIMS_GPIO_PIN_LHL (1<<6)
#define TRIMS_GPIO_REG_LVD pind
#define TRIMS_GPIO_PIN_LVD (1<<3)
#define TRIMS_GPIO_REG_RVU pind
#define TRIMS_GPIO_PIN_RVU (1<<4)
#define TRIMS_GPIO_REG_RHL pind
#define TRIMS_GPIO_PIN_RHL (1<<1)
#define TRIMS_GPIO_REG_LHR pind
#define TRIMS_GPIO_PIN_LHR (1<<7)
#define TRIMS_GPIO_REG_LVU pind
#define TRIMS_GPIO_PIN_LVU (1<<2)
#define TRIMS_GPIO_REG_RVD pind
#define TRIMS_GPIO_PIN_RVD (1<<5)
#define TRIMS_GPIO_REG_RHR pind
#define TRIMS_GPIO_PIN_RHR (1<<0)
#if defined(CPUM2561)
#define TIMER_16KHZ_VECT TIMER2_OVF_vect
#define COUNTER_16KHZ TCNT2
#define TIMER_10MS_VECT TIMER2_COMPA_vect
#define TIMER_10MS_COMPVAL OCR2A
#define PAUSE_10MS_INTERRUPT() TIMSK2 &= ~(1<<OCIE2A)
#define RESUME_10MS_INTERRUPT() TIMSK2 |= (1<<OCIE2A)
#define PAUSE_PPMIN_INTERRUPT() TIMSK3 &= ~(1<<ICIE3)
#define RESUME_PPMIN_INTERRUPT() TIMSK3 |= (1<<ICIE3)
#define TIMER_AUDIO_VECT TIMER4_COMPA_vect
#define SET_TIMER_AUDIO_CTRL() TCCR4B = (1 << WGM42) | (0b010 << CS40)
#define PAUSE_AUDIO_INTERRUPT() TIMSK4 &= ~(1<<OCIE4A)
#define RESUME_AUDIO_INTERRUPT() TIMSK4 |= (1<<OCIE4A)
#else
#define TIMER_16KHZ_VECT TIMER0_OVF_vect
#define COUNTER_16KHZ TCNT0
#define TIMER_10MS_VECT TIMER0_COMP_vect
#define TIMER_10MS_COMPVAL OCR0
#define PAUSE_10MS_INTERRUPT() TIMSK &= ~(1<<OCIE0)
#define RESUME_10MS_INTERRUPT() TIMSK |= (1<<OCIE0)
#define PAUSE_PPMIN_INTERRUPT() ETIMSK &= ~(1<<TICIE3)
#define RESUME_PPMIN_INTERRUPT() ETIMSK |= (1<<TICIE3)
#define TIMER_AUDIO_VECT TIMER2_OVF_vect
#define SET_TIMER_AUDIO_CTRL() TCCR2 = (0b010 << CS00) // Norm mode, clk/8
#define PAUSE_AUDIO_INTERRUPT() TIMSK &= ~(1<<TOIE2)
#define RESUME_AUDIO_INTERRUPT() TIMSK |= (1<<TOIE2)
#endif
// Power driver (none)
#define pwrCheck() (e_power_on)
#define pwrOff()
#define UNEXPECTED_SHUTDOWN() (mcusr & (1 << WDRF))
// Trainer driver
bool checkSlaveMode();
#define OUT_G_SIM_CTL 4 // 1 : phone-jack=ppm_in
#define SLAVE_MODE() checkSlaveMode()
#define JACK_PPM_OUT() PORTG &= ~(1<<OUT_G_SIM_CTL)
#define JACK_PPM_IN() PORTG |= (1<<OUT_G_SIM_CTL)
// Backlight driver
#define OUT_B_LIGHT 7
#if defined(PWM_BACKLIGHT)
void backlightEnable();
void backlightDisable();
bool isBacklightEnabled();
void backlightFade();
#elif defined(SP22)
#define backlightEnable() PORTB &= ~(1<<OUT_B_LIGHT)
#define backlightDisable() PORTB |= (1<<OUT_B_LIGHT)
#define isBacklightEnabled() (~PORTB & (1<<OUT_B_LIGHT))
#else
#define backlightEnable() PORTB |= (1<<OUT_B_LIGHT)
#define backlightDisable() PORTB &= ~(1<<OUT_B_LIGHT)
#define isBacklightEnabled() (PORTB & (1<<OUT_B_LIGHT))
#endif
#if defined(VOICE) && !defined(SIMU)
#define BACKLIGHT_ENABLE() Voice.Backlight = 1
#define BACKLIGHT_DISABLE() Voice.Backlight = 0
#else
#define BACKLIGHT_ENABLE() backlightEnable()
#define BACKLIGHT_DISABLE() backlightDisable()
#endif
#define OUT_B_PPM 0
#define INP_E_PPM_IN 7
#define INP_E_ID2 6
#define INP_E_Trainer 5
#define INP_E_Gear 4
#define OUT_E_BUZZER 3
#define INP_E_ElevDR 2
#if defined(TELEMETRY_JETI) || defined(TELEMETRY_FRSKY) || defined(TELEMETRY_ARDUPILOT) || defined(TELEMETRY_NMEA) || defined(TELEMETRY_MAVLINK)
#define INP_C_ThrCt 6
#define INP_C_AileDR 7
#else
#define INP_E_ThrCt 0
#define INP_E_AileDR 1
#endif
#define INP_G_ID1 3
#define OUT_G_HAPTIC 2
#define INP_G_RF_POW 1
#define INP_G_RuddDR 0
// Rotary Encoder driver
#if defined(ROTARY_ENCODER_NAVIGATION)
extern uint8_t RotEncoder;
#if defined(TELEMETREZ)
#define ROTENC_DOWN() (RotEncoder != 0)
#else
#define ROTENC_DOWN() (RotEncoder & 0x20)
#endif
#else
#define ROTENC_DOWN() (0)
#endif
// Keys driver
inline uint8_t keyDown()
{
return ((~PINB) & 0x7E) | ROTENC_DOWN();
}
#if defined(TELEMETRY_MOD_14051) || defined(TELEMETRY_MOD_14051_SWAPPED)
enum MuxInput {
MUX_BATT,
MUX_AIL,
MUX_PF7_DIGITAL_MIN = MUX_AIL,
MUX_THR,
MUX_TRM_LV_UP,
MUX_TRM_LV_DWN,
MUX_PF7_DIGITAL_MAX = MUX_TRM_LV_DWN,
MUX_MAX = MUX_PF7_DIGITAL_MAX
};
enum Pf7Digital {
PF7_AIL = MUX_AIL - MUX_PF7_DIGITAL_MIN,
PF7_THR = MUX_THR - MUX_PF7_DIGITAL_MIN,
PF7_TRM_LV_UP = MUX_TRM_LV_UP - MUX_PF7_DIGITAL_MIN,
PF7_TRM_LV_DWN = MUX_TRM_LV_DWN - MUX_PF7_DIGITAL_MIN,
};
extern uint8_t pf7_digital[MUX_PF7_DIGITAL_MAX - MUX_PF7_DIGITAL_MIN + 1];
void processMultiplexAna();
#endif
#if defined(TELEMETRY_MOD_14051_SWAPPED)
#define TRIMS_PRESSED() (~PIND & ~0x0c || pf7_digital[PF7_TRM_LV_UP] || pf7_digital[PF7_TRM_LV_DWN])
#else
#define TRIMS_PRESSED() (~PIND)
#endif
#define KEYS_PRESSED() (~PINB)
// LCD driver
#define PORTA_LCD_DAT PORTA
#define PORTC_LCD_CTRL PORTC
#define OUT_C_LCD_E 5
#define OUT_C_LCD_RnW 4
#define OUT_C_LCD_A0 3
#define OUT_C_LCD_RES 2
#define OUT_C_LCD_CS1 1
// Rotary encoder driver
#if defined(ROTARY_ENCODER_NAVIGATION)
extern uint8_t RotEncoder ;
void rotencPoll();
#endif
// Haptic
#define hapticOn() PORTG |= (1 << OUT_G_HAPTIC)
#define hapticOff() PORTG &= ~(1 << OUT_G_HAPTIC)
// USB fake driver
#define usbPlugged() false
// Buzzer driver
#define buzzerOn() PORTE |= (1 << OUT_E_BUZZER)
#define buzzerOff() PORTE &= ~(1 << OUT_E_BUZZER)
#endif // _BOARD_STOCK_H_

View file

@ -1,138 +1,138 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
void lcdSendCtl(uint8_t val)
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
#if defined(LCD_MULTIPLEX)
DDRA = 0xFF; // Set LCD_DAT pins to output
#endif
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
#if defined(LCD_MULTIPLEX)
DDRA = 0x00; // Set LCD_DAT pins to input
#endif
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
const static pm_uchar lcdInitSequence[] PROGMEM =
{
//ST7565 eq. : KS0713, SED1565, S6B1713, SPLC501C, NT7532 /34 /38, TL03245
#if defined(LCD_ST7565R)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA0, //ADC = 0: normal direction (SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA2, //Select LCD bias
0xC8, //SHL = 1: reverse direction (COM64->COM1)
0x2F, //Control power circuit operation VC=VR=VF=1
0x25, //Select int resistance ratio R2 R1 R0 =5
0x81, //Set reference voltage Mode
0x22, //24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
0xAF, //DON = 1: display ON
0x60 //Set the display start line to zero
#elif defined(LCD_ERC12864FSF)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA1, //ADC = 1: reverse direction (SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA3, //Select LCD bias
0xC0, //SHL = 0: normal direction (COM1->COM64)
0x2F, //Control power circuit operation VC=VR=VF=1
0x27, //Select int resistance ratio R2 R1 R0
0x81, //Set reference voltage Mode
0x2D, //24 SV5 SV4 SV3 SV2 SV1 SV0
0xAF //DON = 1: display ON
#else //ST7565P (default 9x LCD)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA1, //ADC = 1: reverse direction(SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA2, //Select LCD bias=0
0xC0, //SHL = 0: normal direction (COM1->COM64)
0x2F, //Control power circuit operation VC=VR=VF=1
0x25, //Select int resistance ratio R2 R1 R0 =5
0x81, //Set reference voltage Mode
0x22, //24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
0xAF //DON = 1: display ON
#endif
};
void lcdInit()
{
LCD_LOCK();
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); // LCD reset
_delay_us(2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // LCD normal operation
_delay_us(1500);
for (uint8_t i=0; i<DIM(lcdInitSequence); i++) {
lcdSendCtl(pgm_read_byte(&lcdInitSequence[i])) ;
}
#if defined(LCD_ERC12864FSF)
g_eeGeneral.contrast = 0x2D;
#else
g_eeGeneral.contrast = 0x22;
#endif
LCD_UNLOCK();
}
void lcdSetRefVolt(uint8_t val)
{
LCD_LOCK();
lcdSendCtl(0x81);
lcdSendCtl(val);
LCD_UNLOCK();
}
void lcdRefresh()
{
LCD_LOCK();
uint8_t * p = displayBuf;
for (uint8_t y=0; y < 8; y++) {
#if defined(LCD_ST7565R)
lcdSendCtl(0x01);
#else
lcdSendCtl(0x04);
#endif
lcdSendCtl(0x10); // Column addr 0
lcdSendCtl( y | 0xB0); //Page addr y
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
#if defined(LCD_MULTIPLEX)
DDRA = 0xFF; // Set LCD_DAT pins to output
#endif
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
for (coord_t x=LCD_W; x>0; --x) {
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
}
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
LCD_UNLOCK();
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
void lcdSendCtl(uint8_t val)
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
#if defined(LCD_MULTIPLEX)
DDRA = 0xFF; // Set LCD_DAT pins to output
#endif
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
#if defined(LCD_MULTIPLEX)
DDRA = 0x00; // Set LCD_DAT pins to input
#endif
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
const static pm_uchar lcdInitSequence[] PROGMEM =
{
//ST7565 eq. : KS0713, SED1565, S6B1713, SPLC501C, NT7532 /34 /38, TL03245
#if defined(LCD_ST7565R)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA0, //ADC = 0: normal direction (SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA2, //Select LCD bias
0xC8, //SHL = 1: reverse direction (COM64->COM1)
0x2F, //Control power circuit operation VC=VR=VF=1
0x25, //Select int resistance ratio R2 R1 R0 =5
0x81, //Set reference voltage Mode
0x22, //24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
0xAF, //DON = 1: display ON
0x60 //Set the display start line to zero
#elif defined(LCD_ERC12864FSF)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA1, //ADC = 1: reverse direction (SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA3, //Select LCD bias
0xC0, //SHL = 0: normal direction (COM1->COM64)
0x2F, //Control power circuit operation VC=VR=VF=1
0x27, //Select int resistance ratio R2 R1 R0
0x81, //Set reference voltage Mode
0x2D, //24 SV5 SV4 SV3 SV2 SV1 SV0
0xAF //DON = 1: display ON
#else //ST7565P (default 9x LCD)
0xE2, //Initialize the internal functions
0xAE, //DON = 0: display OFF
0xA1, //ADC = 1: reverse direction(SEG132->SEG1)
0xA6, //REV = 0: non-reverse display
0xA4, //EON = 0: normal display. non-entire
0xA2, //Select LCD bias=0
0xC0, //SHL = 0: normal direction (COM1->COM64)
0x2F, //Control power circuit operation VC=VR=VF=1
0x25, //Select int resistance ratio R2 R1 R0 =5
0x81, //Set reference voltage Mode
0x22, //24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
0xAF //DON = 1: display ON
#endif
};
void lcdInit()
{
LCD_LOCK();
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); // LCD reset
_delay_us(2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // LCD normal operation
_delay_us(1500);
for (uint8_t i=0; i<DIM(lcdInitSequence); i++) {
lcdSendCtl(pgm_read_byte(&lcdInitSequence[i])) ;
}
#if defined(LCD_ERC12864FSF)
g_eeGeneral.contrast = 0x2D;
#else
g_eeGeneral.contrast = 0x22;
#endif
LCD_UNLOCK();
}
void lcdSetRefVolt(uint8_t val)
{
LCD_LOCK();
lcdSendCtl(0x81);
lcdSendCtl(val);
LCD_UNLOCK();
}
void lcdRefresh()
{
LCD_LOCK();
uint8_t * p = displayBuf;
for (uint8_t y=0; y < 8; y++) {
#if defined(LCD_ST7565R)
lcdSendCtl(0x01);
#else
lcdSendCtl(0x04);
#endif
lcdSendCtl(0x10); // Column addr 0
lcdSendCtl( y | 0xB0); //Page addr y
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
#if defined(LCD_MULTIPLEX)
DDRA = 0xFF; // Set LCD_DAT pins to output
#endif
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
for (coord_t x=LCD_W; x>0; --x) {
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
}
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
LCD_UNLOCK();
}

View file

@ -1,38 +1,38 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#if defined(PCBSTD) && defined(VOICE)
volatile uint8_t LcdLock;
#define LCD_LOCK() LcdLock = 1
#define LCD_UNLOCK() LcdLock = 0
#else
#define LCD_LOCK()
#define LCD_UNLOCK()
#endif
#if defined(LCD_KS108)
#include "targets/9x/lcd_ks108_driver.cpp"
#elif defined(LCD_ST7920)
#include "targets/9x/lcd_st7920_driver.cpp"
#else
#include "targets/9x/lcd_default_driver.cpp"
#endif
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#if defined(PCBSTD) && defined(VOICE)
volatile uint8_t LcdLock;
#define LCD_LOCK() LcdLock = 1
#define LCD_UNLOCK() LcdLock = 0
#else
#define LCD_LOCK()
#define LCD_UNLOCK()
#endif
#if defined(LCD_KS108)
#include "targets/9x/lcd_ks108_driver.cpp"
#elif defined(LCD_ST7920)
#include "targets/9x/lcd_st7920_driver.cpp"
#else
#include "targets/9x/lcd_default_driver.cpp"
#endif

View file

@ -1,92 +1,92 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define DISPLAY_SET_COLUMN 0x40
#define DISPLAY_SET_PAGE 0xB8
#define DISPLAY_SET_START 0XC0
#define DISPLAY_ON_CMD 0x3F
#define CS1_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1)
#define CS1_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1)
#define CS2_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS2)
#define CS2_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS2)
#define A0_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0)
#define A0_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0)
#define E_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E)
#define E_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E)
void lcdPulseEnable(void)
{
E_on;
_delay_us(4);
E_off;
}
void lcdSendCtl(uint8_t val)
{
PORTA_LCD_DAT = val;
A0_off;
lcdPulseEnable();
A0_on;
}
void lcdInit()
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD reset
_delay_us(20);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); //LCD normal operation
CS1_on;
lcdSendCtl(DISPLAY_ON_CMD);
lcdSendCtl(DISPLAY_SET_START);
CS1_off;
CS2_on;
lcdSendCtl(DISPLAY_ON_CMD);
lcdSendCtl(DISPLAY_SET_START);
CS2_off;
}
void lcdSetRefVolt(uint8_t val)
{
}
void lcdRefreshSide()
{
static uint8_t change = 0; // toggle left or right lcd writing
uint8_t *p;
if (change == 0){ CS2_off; CS1_on; p = displayBuf; change = 1;} // Right
else{ CS1_off; CS2_on; p = displayBuf + 64; change = 0;} // Left
for (uint8_t page=0; page < 8; page++) {
lcdSendCtl(DISPLAY_SET_COLUMN); // Column addr 0
lcdSendCtl( page | DISPLAY_SET_PAGE); //Page addr
A0_on;
for (coord_t x=64; x>0; --x) {
PORTA_LCD_DAT = *p++;
lcdPulseEnable();
}
p += 64;
}
A0_off;
}
void lcdRefresh()
{
lcdRefreshSide();
lcdRefreshSide();
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define DISPLAY_SET_COLUMN 0x40
#define DISPLAY_SET_PAGE 0xB8
#define DISPLAY_SET_START 0XC0
#define DISPLAY_ON_CMD 0x3F
#define CS1_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1)
#define CS1_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1)
#define CS2_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS2)
#define CS2_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS2)
#define A0_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0)
#define A0_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0)
#define E_on PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E)
#define E_off PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E)
void lcdPulseEnable(void)
{
E_on;
_delay_us(4);
E_off;
}
void lcdSendCtl(uint8_t val)
{
PORTA_LCD_DAT = val;
A0_off;
lcdPulseEnable();
A0_on;
}
void lcdInit()
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD reset
_delay_us(20);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); //LCD normal operation
CS1_on;
lcdSendCtl(DISPLAY_ON_CMD);
lcdSendCtl(DISPLAY_SET_START);
CS1_off;
CS2_on;
lcdSendCtl(DISPLAY_ON_CMD);
lcdSendCtl(DISPLAY_SET_START);
CS2_off;
}
void lcdSetRefVolt(uint8_t val)
{
}
void lcdRefreshSide()
{
static uint8_t change = 0; // toggle left or right lcd writing
uint8_t *p;
if (change == 0){ CS2_off; CS1_on; p = displayBuf; change = 1;} // Right
else{ CS1_off; CS2_on; p = displayBuf + 64; change = 0;} // Left
for (uint8_t page=0; page < 8; page++) {
lcdSendCtl(DISPLAY_SET_COLUMN); // Column addr 0
lcdSendCtl( page | DISPLAY_SET_PAGE); //Page addr
A0_on;
for (coord_t x=64; x>0; --x) {
PORTA_LCD_DAT = *p++;
lcdPulseEnable();
}
p += 64;
}
A0_off;
}
void lcdRefresh()
{
lcdRefreshSide();
lcdRefreshSide();
}

View file

@ -1,137 +1,137 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
void lcdSendCtl(uint8_t val)
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
const static pm_uchar lcdInitSequence[] PROGMEM =
{
0x30, // Set 8-bit interface
0x36, // Repeat with graphics bit set to ON
0x0C, // Display ON, cursor and blink OFF
0x01, // Clear display, reset address
0x06 // Display ON, no cursor
};
void lcdInit()
{
LCD_LOCK();
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD reset
_delay_us(2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); //LCD normal operation
_delay_ms(40);
for (uint8_t i=0; i<DIM(lcdInitSequence); i++) {
lcdSendCtl(pgm_read_byte(&lcdInitSequence[i])) ;
_delay_us(80);
}
g_eeGeneral.contrast = 0x22;
LCD_UNLOCK();
}
void lcdSetRefVolt(uint8_t val)
{
}
uint8_t lcdRefresh_ST7920(uint8_t full)
{
LCD_LOCK();
static uint8_t state;
uint8_t yst;
uint8_t yend;
uint8_t y_table[6]={0,13,26,39,52,64};
uint8_t x_addr = 0;
uint8_t y_addr = 0;
uint16_t line_offset = 0;
uint8_t col_offset = 0;
uint8_t bit_count = 0;
uint8_t result;
uint8_t *p;
if(full!=0){
yst=0;
yend=64;
state=0;
}
else{ //Since writing to ST7920 is too slow we need to split it to five bands
yst=y_table[state];
yend=y_table[state+1];
if (state==4){
state=0;
}
else{
state++;
}
}
for (uint8_t y=yst; y<yend; y++) {
x_addr = 0;
//Convert coordinates to weirdly-arranged 128x64 screen (the ST7920 is mapped for 256x32 displays)
if (y > 31) {
y_addr = y - 32; //Because there are only 31 addressable lines in the ST7920
x_addr += 8; //so we overflow x (7 visible bytes per line) to reach the bottom half
}
else {
y_addr = y;
}
lcdSendCtl( 0x80 | y_addr ); //Set Vertical Address
_delay_us(49);
lcdSendCtl( 0x80 | x_addr ); //Set Horizontal Address
_delay_us(49);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0); //HIGH RS and LOW RW will put the LCD to
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW); //Write data register mode
bit_count = y & 0x07; //Count from 0 bis 7 -> 0=0, 1=1..7=7, 8=0, 9=1...
col_offset = 1 << bit_count; //Build a value for a AND operation with the vorrect bitposition
line_offset = ( y / 8 ) * 128; //On the ST7565 there are 8 lines with each 128 bytes width
for (coord_t x=0; x<16; x++) { //Walk through 16 bytes form left to right (128 Pixel)
p = displayBuf + line_offset + ( x * 8 ); //Calculate the position of the first byte im array
// adressing the bytes sequential and set the bits at the correct position merging them with an OR operation to get all bits in one byte
// the position of the LSB is the right-most position of the byte to the ST7920
result = ((*p++ & col_offset)!=0?0x80:0);
result |= ((*p++ & col_offset)!=0?0x40:0);
result |= ((*p++ & col_offset)!=0?0x20:0);
result |= ((*p++ & col_offset)!=0?0x10:0);
result |= ((*p++ & col_offset)!=0?0x08:0);
result |= ((*p++ & col_offset)!=0?0x04:0);
result |= ((*p++ & col_offset) !=0?0x02:0);
result |= ((*p++ & col_offset)!=0?0x01:0);
PORTA_LCD_DAT = result;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
_delay_us(8);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
_delay_us(49);
}
}
LCD_UNLOCK();
return state;
}
void lcdRefresh()
{
lcdRefresh_ST7920(1);
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
void lcdSendCtl(uint8_t val)
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
const static pm_uchar lcdInitSequence[] PROGMEM =
{
0x30, // Set 8-bit interface
0x36, // Repeat with graphics bit set to ON
0x0C, // Display ON, cursor and blink OFF
0x01, // Clear display, reset address
0x06 // Display ON, no cursor
};
void lcdInit()
{
LCD_LOCK();
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD reset
_delay_us(2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); //LCD normal operation
_delay_ms(40);
for (uint8_t i=0; i<DIM(lcdInitSequence); i++) {
lcdSendCtl(pgm_read_byte(&lcdInitSequence[i])) ;
_delay_us(80);
}
g_eeGeneral.contrast = 0x22;
LCD_UNLOCK();
}
void lcdSetRefVolt(uint8_t val)
{
}
uint8_t lcdRefresh_ST7920(uint8_t full)
{
LCD_LOCK();
static uint8_t state;
uint8_t yst;
uint8_t yend;
uint8_t y_table[6]={0,13,26,39,52,64};
uint8_t x_addr = 0;
uint8_t y_addr = 0;
uint16_t line_offset = 0;
uint8_t col_offset = 0;
uint8_t bit_count = 0;
uint8_t result;
uint8_t *p;
if(full!=0){
yst=0;
yend=64;
state=0;
}
else{ //Since writing to ST7920 is too slow we need to split it to five bands
yst=y_table[state];
yend=y_table[state+1];
if (state==4){
state=0;
}
else{
state++;
}
}
for (uint8_t y=yst; y<yend; y++) {
x_addr = 0;
//Convert coordinates to weirdly-arranged 128x64 screen (the ST7920 is mapped for 256x32 displays)
if (y > 31) {
y_addr = y - 32; //Because there are only 31 addressable lines in the ST7920
x_addr += 8; //so we overflow x (7 visible bytes per line) to reach the bottom half
}
else {
y_addr = y;
}
lcdSendCtl( 0x80 | y_addr ); //Set Vertical Address
_delay_us(49);
lcdSendCtl( 0x80 | x_addr ); //Set Horizontal Address
_delay_us(49);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0); //HIGH RS and LOW RW will put the LCD to
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW); //Write data register mode
bit_count = y & 0x07; //Count from 0 bis 7 -> 0=0, 1=1..7=7, 8=0, 9=1...
col_offset = 1 << bit_count; //Build a value for a AND operation with the vorrect bitposition
line_offset = ( y / 8 ) * 128; //On the ST7565 there are 8 lines with each 128 bytes width
for (coord_t x=0; x<16; x++) { //Walk through 16 bytes form left to right (128 Pixel)
p = displayBuf + line_offset + ( x * 8 ); //Calculate the position of the first byte im array
// adressing the bytes sequential and set the bits at the correct position merging them with an OR operation to get all bits in one byte
// the position of the LSB is the right-most position of the byte to the ST7920
result = ((*p++ & col_offset)!=0?0x80:0);
result |= ((*p++ & col_offset)!=0?0x40:0);
result |= ((*p++ & col_offset)!=0?0x20:0);
result |= ((*p++ & col_offset)!=0?0x10:0);
result |= ((*p++ & col_offset)!=0?0x08:0);
result |= ((*p++ & col_offset)!=0?0x04:0);
result |= ((*p++ & col_offset) !=0?0x02:0);
result |= ((*p++ & col_offset)!=0?0x01:0);
PORTA_LCD_DAT = result;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
_delay_us(8);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
_delay_us(49);
}
}
LCD_UNLOCK();
return state;
}
void lcdRefresh()
{
lcdRefresh_ST7920(1);
}

View file

@ -1,139 +1,139 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
struct t_voice Voice ;
void pushPrompt(uint16_t value)
{
#ifdef SIMU
TRACE("playFile(\"%04d.ad4\")", value);
#endif
struct t_voice *vptr;
vptr = voiceaddress();
if (vptr->VoiceQueueCount < VOICE_Q_LENGTH) {
vptr->VoiceQueue[vptr->VoiceQueueInIndex++] = value;
vptr->VoiceQueueInIndex &= (VOICE_Q_LENGTH - 1);
vptr->VoiceQueueCount += 1;
}
}
void pushCustomPrompt(uint8_t value)
{
pushPrompt(PROMPT_CUSTOM_BASE + value);
}
void pushNumberPrompt(uint8_t value)
{
pushPrompt(PROMPT_I18N_BASE + value);
}
struct t_voice *voiceaddress()
{
return &Voice ;
}
void t_voice::voice_process(void)
{
if (Backlight)
VoiceLatch |= BACKLIGHT_BIT;
else
VoiceLatch &= ~BACKLIGHT_BIT;
if (VoiceState == V_IDLE) {
PORTB |= (1 << OUT_B_LIGHT); // Latch clock high
if (VoiceQueueCount) {
VoiceSerial = VoiceQueue[VoiceQueueOutIndex++];
VoiceQueueOutIndex &= (VOICE_Q_LENGTH - 1);
VoiceQueueCount -= 1;
VoiceTimer = 17;
if (VoiceSerial & 0x8000) { // Looking for sound volume 1F0-1F7
VoiceTimer = 40;
}
VoiceLatch &= ~VOICE_CLOCK_BIT & ~VOICE_DATA_BIT ;
if (VoiceSerial & 0x8000) {
VoiceLatch |= VOICE_DATA_BIT;
}
PORTA_LCD_DAT = VoiceLatch ; // Latch data set
PORTB &= ~(1<<OUT_B_LIGHT) ; // Latch clock low
VoiceCounter = 31;
VoiceState = V_CLOCKING;
}
else {
PORTA_LCD_DAT = VoiceLatch; // Latch data set
PORTB &= ~(1 << OUT_B_LIGHT); // Latch clock low
}
}
else if (VoiceState == V_STARTUP) {
PORTB |= (1<<OUT_B_LIGHT) ; // Latch clock high
VoiceLatch |= VOICE_CLOCK_BIT | VOICE_DATA_BIT ;
PORTA_LCD_DAT = VoiceLatch ; // Latch data set
if (g_blinkTmr10ms > 60) { // Give module 1.4 secs to initialise
VoiceState = V_WAIT_START_BUSY_OFF ;
}
PORTB &= ~(1<<OUT_B_LIGHT) ; // Latch clock low
}
else if (VoiceState != V_CLOCKING) {
uint8_t busy;
PORTA_LCD_DAT = VoiceLatch; // Latch data set
PORTB |= (1 << OUT_B_LIGHT); // Drive high,pullup enabled
DDRB &= ~(1 << OUT_B_LIGHT); // Change to input
// delay to allow input to settle
asm(" rjmp 1f");
asm("1:");
asm(" nop");
asm(" rjmp 1f");
asm("1:");
busy = PINB & 0x80;
DDRB |= (1 << OUT_B_LIGHT); // Change to output
// The next bit guarantees the backlight output gets clocked out
if (VoiceState == V_WAIT_BUSY_ON) { // check for busy processing here
if (busy == 0) { // Busy is active
VoiceState = V_WAIT_BUSY_OFF;
}
else {
if (--VoiceTimer == 0) {
VoiceState = V_WAIT_BUSY_OFF;
}
}
}
else if (VoiceState == V_WAIT_BUSY_OFF) { // check for busy processing here
if (busy) { // Busy is inactive
VoiceTimer = 3;
VoiceState = V_WAIT_BUSY_DELAY;
}
}
else if (VoiceState == V_WAIT_BUSY_DELAY) {
if (--VoiceTimer == 0) {
VoiceState = V_IDLE;
}
}
else if (VoiceState == V_WAIT_START_BUSY_OFF) { // check for busy processing here
if (busy) { // Busy is inactive
VoiceTimer = 20 ;
VoiceState = V_WAIT_BUSY_DELAY ;
}
}
PORTB &= ~(1 << OUT_B_LIGHT); // Latch clock low
}
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
struct t_voice Voice ;
void pushPrompt(uint16_t value)
{
#ifdef SIMU
TRACE("playFile(\"%04d.ad4\")", value);
#endif
struct t_voice *vptr;
vptr = voiceaddress();
if (vptr->VoiceQueueCount < VOICE_Q_LENGTH) {
vptr->VoiceQueue[vptr->VoiceQueueInIndex++] = value;
vptr->VoiceQueueInIndex &= (VOICE_Q_LENGTH - 1);
vptr->VoiceQueueCount += 1;
}
}
void pushCustomPrompt(uint8_t value)
{
pushPrompt(PROMPT_CUSTOM_BASE + value);
}
void pushNumberPrompt(uint8_t value)
{
pushPrompt(PROMPT_I18N_BASE + value);
}
struct t_voice *voiceaddress()
{
return &Voice ;
}
void t_voice::voice_process(void)
{
if (Backlight)
VoiceLatch |= BACKLIGHT_BIT;
else
VoiceLatch &= ~BACKLIGHT_BIT;
if (VoiceState == V_IDLE) {
PORTB |= (1 << OUT_B_LIGHT); // Latch clock high
if (VoiceQueueCount) {
VoiceSerial = VoiceQueue[VoiceQueueOutIndex++];
VoiceQueueOutIndex &= (VOICE_Q_LENGTH - 1);
VoiceQueueCount -= 1;
VoiceTimer = 17;
if (VoiceSerial & 0x8000) { // Looking for sound volume 1F0-1F7
VoiceTimer = 40;
}
VoiceLatch &= ~VOICE_CLOCK_BIT & ~VOICE_DATA_BIT ;
if (VoiceSerial & 0x8000) {
VoiceLatch |= VOICE_DATA_BIT;
}
PORTA_LCD_DAT = VoiceLatch ; // Latch data set
PORTB &= ~(1<<OUT_B_LIGHT) ; // Latch clock low
VoiceCounter = 31;
VoiceState = V_CLOCKING;
}
else {
PORTA_LCD_DAT = VoiceLatch; // Latch data set
PORTB &= ~(1 << OUT_B_LIGHT); // Latch clock low
}
}
else if (VoiceState == V_STARTUP) {
PORTB |= (1<<OUT_B_LIGHT) ; // Latch clock high
VoiceLatch |= VOICE_CLOCK_BIT | VOICE_DATA_BIT ;
PORTA_LCD_DAT = VoiceLatch ; // Latch data set
if (g_blinkTmr10ms > 60) { // Give module 1.4 secs to initialise
VoiceState = V_WAIT_START_BUSY_OFF ;
}
PORTB &= ~(1<<OUT_B_LIGHT) ; // Latch clock low
}
else if (VoiceState != V_CLOCKING) {
uint8_t busy;
PORTA_LCD_DAT = VoiceLatch; // Latch data set
PORTB |= (1 << OUT_B_LIGHT); // Drive high,pullup enabled
DDRB &= ~(1 << OUT_B_LIGHT); // Change to input
// delay to allow input to settle
asm(" rjmp 1f");
asm("1:");
asm(" nop");
asm(" rjmp 1f");
asm("1:");
busy = PINB & 0x80;
DDRB |= (1 << OUT_B_LIGHT); // Change to output
// The next bit guarantees the backlight output gets clocked out
if (VoiceState == V_WAIT_BUSY_ON) { // check for busy processing here
if (busy == 0) { // Busy is active
VoiceState = V_WAIT_BUSY_OFF;
}
else {
if (--VoiceTimer == 0) {
VoiceState = V_WAIT_BUSY_OFF;
}
}
}
else if (VoiceState == V_WAIT_BUSY_OFF) { // check for busy processing here
if (busy) { // Busy is inactive
VoiceTimer = 3;
VoiceState = V_WAIT_BUSY_DELAY;
}
}
else if (VoiceState == V_WAIT_BUSY_DELAY) {
if (--VoiceTimer == 0) {
VoiceState = V_IDLE;
}
}
else if (VoiceState == V_WAIT_START_BUSY_OFF) { // check for busy processing here
if (busy) { // Busy is inactive
VoiceTimer = 20 ;
VoiceState = V_WAIT_BUSY_DELAY ;
}
}
PORTB &= ~(1 << OUT_B_LIGHT); // Latch clock low
}
}

View file

@ -1,125 +1,125 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
// Bits in VoiceLatch
#define VOICE_CLOCK_BIT 0x01
#define VOICE_DATA_BIT 0x02
#define BACKLIGHT_BIT 0x04
#define SPARE_BIT 0x08
#if defined(CPUM64)
#define VOICE_Q_LENGTH 8
#else
#define VOICE_Q_LENGTH 16
#endif
// Voice states
#define V_STARTUP 0
#define V_IDLE 1
#define V_CLOCKING 2
#define V_WAIT_BUSY_ON 3
#define V_WAIT_BUSY_OFF 4
#define V_WAIT_BUSY_DELAY 5
#define V_WAIT_START_BUSY_OFF 6
#define PROMPT_CUSTOM_BASE 0
#define PROMPT_I18N_BASE 256
#define PROMPT_SYSTEM_BASE 480
struct t_voice
{
uint16_t VoiceQueue[VOICE_Q_LENGTH] ;
uint8_t Backlight ;
uint8_t VoiceLatch ;
uint8_t VoiceCounter ;
uint8_t VoiceTimer ;
uint16_t VoiceSerial ;
uint8_t VoiceState ;
uint8_t VoiceQueueCount ;
uint8_t VoiceQueueInIndex ;
uint8_t VoiceQueueOutIndex ;
void voice_process( void ) ;
};
extern void pushPrompt(uint16_t value);
extern void pushCustomPrompt(uint8_t value);
extern void pushNumberPrompt(uint8_t value);
extern struct t_voice *voiceaddress( void ) ;
extern struct t_voice Voice ;
#define VOLUME_LEVEL_MAX 7
#define VOLUME_LEVEL_DEF 7
#define setScaledVolume(v) pushPrompt((v) | 0xFFF0)
inline bool isPlaying()
{
#if defined(SIMU)
return false;
#else
return Voice.VoiceState != V_IDLE;
#endif
}
/*
* Handle the Voice output
* Check for LcdLocked (in interrupt), and voice_enabled
*/
#define VOICE_DRIVER() \
if ( LcdLock == 0 ) { /* LCD not in use */ \
struct t_voice *vptr; \
vptr = voiceaddress(); \
if ( vptr->VoiceState == V_CLOCKING ) { \
if ( vptr->VoiceTimer ) { \
vptr->VoiceTimer -= 1; \
} \
else { \
PORTB |= (1<<OUT_B_LIGHT); /* Latch clock high */ \
if ((vptr->VoiceCounter & 1) == 0) { \
vptr->VoiceLatch &= ~VOICE_DATA_BIT; \
if ( vptr->VoiceSerial & 0x4000 ) { \
vptr->VoiceLatch |= VOICE_DATA_BIT; \
} \
vptr->VoiceSerial <<= 1; \
} \
vptr->VoiceLatch ^= VOICE_CLOCK_BIT; \
PORTA_LCD_DAT = vptr->VoiceLatch; /* Latch data set */ \
PORTB &= ~(1<<OUT_B_LIGHT); /* Latch clock low */ \
if ( --vptr->VoiceCounter == 0 ) { \
vptr->VoiceState = V_WAIT_BUSY_ON; \
vptr->VoiceTimer = 5; /* 50 mS */ \
} \
} \
} \
}
#define I18N_PLAY_FUNCTION(lng, x, ...) void x(__VA_ARGS__)
#define PLAY_FUNCTION(x, ...) void x(__VA_ARGS__)
#define PUSH_CUSTOM_PROMPT(p, ...) pushCustomPrompt((p))
#define PUSH_NUMBER_PROMPT(p) pushNumberPrompt((p))
#define PUSH_SYSTEM_PROMPT(p) pushNumberPrompt(PROMPT_SYSTEM_BASE-PROMPT_I18N_BASE+(p))
#define PLAY_NUMBER(n, u, a) playNumber((n), (u), (a))
#define PLAY_DURATION(d, att) playDuration((d))
#define PLAY_DURATION_ATT
#define PLAY_TIME
#define IS_PLAY_TIME() (0)
#define IS_PLAYING(id) (0) /* isPlaying() */
#define PLAY_VALUE(v, id) playValue((v))
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
// Bits in VoiceLatch
#define VOICE_CLOCK_BIT 0x01
#define VOICE_DATA_BIT 0x02
#define BACKLIGHT_BIT 0x04
#define SPARE_BIT 0x08
#if defined(CPUM64)
#define VOICE_Q_LENGTH 8
#else
#define VOICE_Q_LENGTH 16
#endif
// Voice states
#define V_STARTUP 0
#define V_IDLE 1
#define V_CLOCKING 2
#define V_WAIT_BUSY_ON 3
#define V_WAIT_BUSY_OFF 4
#define V_WAIT_BUSY_DELAY 5
#define V_WAIT_START_BUSY_OFF 6
#define PROMPT_CUSTOM_BASE 0
#define PROMPT_I18N_BASE 256
#define PROMPT_SYSTEM_BASE 480
struct t_voice
{
uint16_t VoiceQueue[VOICE_Q_LENGTH] ;
uint8_t Backlight ;
uint8_t VoiceLatch ;
uint8_t VoiceCounter ;
uint8_t VoiceTimer ;
uint16_t VoiceSerial ;
uint8_t VoiceState ;
uint8_t VoiceQueueCount ;
uint8_t VoiceQueueInIndex ;
uint8_t VoiceQueueOutIndex ;
void voice_process( void ) ;
};
extern void pushPrompt(uint16_t value);
extern void pushCustomPrompt(uint8_t value);
extern void pushNumberPrompt(uint8_t value);
extern struct t_voice *voiceaddress( void ) ;
extern struct t_voice Voice ;
#define VOLUME_LEVEL_MAX 7
#define VOLUME_LEVEL_DEF 7
#define setScaledVolume(v) pushPrompt((v) | 0xFFF0)
inline bool isPlaying()
{
#if defined(SIMU)
return false;
#else
return Voice.VoiceState != V_IDLE;
#endif
}
/*
* Handle the Voice output
* Check for LcdLocked (in interrupt), and voice_enabled
*/
#define VOICE_DRIVER() \
if ( LcdLock == 0 ) { /* LCD not in use */ \
struct t_voice *vptr; \
vptr = voiceaddress(); \
if ( vptr->VoiceState == V_CLOCKING ) { \
if ( vptr->VoiceTimer ) { \
vptr->VoiceTimer -= 1; \
} \
else { \
PORTB |= (1<<OUT_B_LIGHT); /* Latch clock high */ \
if ((vptr->VoiceCounter & 1) == 0) { \
vptr->VoiceLatch &= ~VOICE_DATA_BIT; \
if ( vptr->VoiceSerial & 0x4000 ) { \
vptr->VoiceLatch |= VOICE_DATA_BIT; \
} \
vptr->VoiceSerial <<= 1; \
} \
vptr->VoiceLatch ^= VOICE_CLOCK_BIT; \
PORTA_LCD_DAT = vptr->VoiceLatch; /* Latch data set */ \
PORTB &= ~(1<<OUT_B_LIGHT); /* Latch clock low */ \
if ( --vptr->VoiceCounter == 0 ) { \
vptr->VoiceState = V_WAIT_BUSY_ON; \
vptr->VoiceTimer = 5; /* 50 mS */ \
} \
} \
} \
}
#define I18N_PLAY_FUNCTION(lng, x, ...) void x(__VA_ARGS__)
#define PLAY_FUNCTION(x, ...) void x(__VA_ARGS__)
#define PUSH_CUSTOM_PROMPT(p, ...) pushCustomPrompt((p))
#define PUSH_NUMBER_PROMPT(p) pushNumberPrompt((p))
#define PUSH_SYSTEM_PROMPT(p) pushNumberPrompt(PROMPT_SYSTEM_BASE-PROMPT_I18N_BASE+(p))
#define PLAY_NUMBER(n, u, a) playNumber((n), (u), (a))
#define PLAY_DURATION(d, att) playDuration((d))
#define PLAY_DURATION_ATT
#define PLAY_TIME
#define IS_PLAY_TIME() (0)
#define IS_PLAYING(id) (0) /* isPlaying() */
#define PLAY_VALUE(v, id) playValue((v))

View file

@ -1,56 +1,56 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <OsConfig.h>
#include "board.h"
#if defined(STM32F2)
#include "dwt.h" // the old ST library that we use does not define DWT register for STM32F2xx
#endif
#define SYSTEM_TICKS_1US ((CFG_CPU_FREQ + 500000) / 1000000) // number of system ticks in 1us
#define SYSTEM_TICKS_01US ((CFG_CPU_FREQ + 5000000) / 10000000) // number of system ticks in 0.1us (rounding needed for sys frequencies that are not multiple of 10MHz)
void delaysInit(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
void delay_01us(uint16_t nb)
{
volatile uint32_t dwtStart = DWT->CYCCNT;
volatile uint32_t dwtTotal = (SYSTEM_TICKS_01US * nb) - 10;
while ((DWT->CYCCNT - dwtStart) < dwtTotal);
}
void delay_us(uint16_t nb)
{
volatile uint32_t dwtStart = DWT->CYCCNT;
volatile uint32_t dwtTotal = (SYSTEM_TICKS_1US * nb) - 10;
while ((DWT->CYCCNT - dwtStart) < dwtTotal);
}
void delay_ms(uint32_t ms)
{
while (ms--) {
delay_us(1000);
}
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <OsConfig.h>
#include "board.h"
#if defined(STM32F2)
#include "dwt.h" // the old ST library that we use does not define DWT register for STM32F2xx
#endif
#define SYSTEM_TICKS_1US ((CFG_CPU_FREQ + 500000) / 1000000) // number of system ticks in 1us
#define SYSTEM_TICKS_01US ((CFG_CPU_FREQ + 5000000) / 10000000) // number of system ticks in 0.1us (rounding needed for sys frequencies that are not multiple of 10MHz)
void delaysInit(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
void delay_01us(uint16_t nb)
{
volatile uint32_t dwtStart = DWT->CYCCNT;
volatile uint32_t dwtTotal = (SYSTEM_TICKS_01US * nb) - 10;
while ((DWT->CYCCNT - dwtStart) < dwtTotal);
}
void delay_us(uint16_t nb)
{
volatile uint32_t dwtStart = DWT->CYCCNT;
volatile uint32_t dwtTotal = (SYSTEM_TICKS_1US * nb) - 10;
while ((DWT->CYCCNT - dwtStart) < dwtTotal);
}
void delay_ms(uint32_t ms)
{
while (ms--) {
delay_us(1000);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,86 +1,86 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void rtcSetTime(const struct gtm * t)
{
g_ms100 = 0; // start of next second begins now
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
RTC_TimeStructInit(&RTC_TimeStruct);
RTC_DateStructInit(&RTC_DateStruct);
RTC_TimeStruct.RTC_Hours = t->tm_hour;
RTC_TimeStruct.RTC_Minutes = t->tm_min;
RTC_TimeStruct.RTC_Seconds = t->tm_sec;
RTC_DateStruct.RTC_Year = t->tm_year - 100;
RTC_DateStruct.RTC_Month = t->tm_mon + 1;
RTC_DateStruct.RTC_Date = t->tm_mday;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct);
}
void rtcGetTime(struct gtm * t)
{
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
t->tm_hour = RTC_TimeStruct.RTC_Hours;
t->tm_min = RTC_TimeStruct.RTC_Minutes;
t->tm_sec = RTC_TimeStruct.RTC_Seconds;
t->tm_year = RTC_DateStruct.RTC_Year + 100; // STM32 year is two decimals only (so base is currently 2000), gtm is based on number of years since 1900
t->tm_mon = RTC_DateStruct.RTC_Month - 1;
t->tm_mday = RTC_DateStruct.RTC_Date;
}
void rtcInit()
{
RTC_InitTypeDef RTC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RCC_LSEConfig(RCC_LSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
// RTC time base = LSE / ((AsynchPrediv+1) * (SynchPrediv+1)) = 1 Hz*/
RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
RTC_InitStruct.RTC_AsynchPrediv = 127;
RTC_InitStruct.RTC_SynchPrediv = 255;
RTC_Init(&RTC_InitStruct);
struct gtm utm;
rtcGetTime(&utm);
g_rtcTime = gmktime(&utm);
#if defined(RAMBACKUP)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
PWR_BackupRegulatorCmd(ENABLE);
#endif
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void rtcSetTime(const struct gtm * t)
{
g_ms100 = 0; // start of next second begins now
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
RTC_TimeStructInit(&RTC_TimeStruct);
RTC_DateStructInit(&RTC_DateStruct);
RTC_TimeStruct.RTC_Hours = t->tm_hour;
RTC_TimeStruct.RTC_Minutes = t->tm_min;
RTC_TimeStruct.RTC_Seconds = t->tm_sec;
RTC_DateStruct.RTC_Year = t->tm_year - 100;
RTC_DateStruct.RTC_Month = t->tm_mon + 1;
RTC_DateStruct.RTC_Date = t->tm_mday;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct);
}
void rtcGetTime(struct gtm * t)
{
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
t->tm_hour = RTC_TimeStruct.RTC_Hours;
t->tm_min = RTC_TimeStruct.RTC_Minutes;
t->tm_sec = RTC_TimeStruct.RTC_Seconds;
t->tm_year = RTC_DateStruct.RTC_Year + 100; // STM32 year is two decimals only (so base is currently 2000), gtm is based on number of years since 1900
t->tm_mon = RTC_DateStruct.RTC_Month - 1;
t->tm_mday = RTC_DateStruct.RTC_Date;
}
void rtcInit()
{
RTC_InitTypeDef RTC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RCC_LSEConfig(RCC_LSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
// RTC time base = LSE / ((AsynchPrediv+1) * (SynchPrediv+1)) = 1 Hz*/
RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
RTC_InitStruct.RTC_AsynchPrediv = 127;
RTC_InitStruct.RTC_SynchPrediv = 255;
RTC_Init(&RTC_InitStruct);
struct gtm utm;
rtcGetTime(&utm);
g_rtcTime = gmktime(&utm);
#if defined(RAMBACKUP)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
PWR_BackupRegulatorCmd(ENABLE);
#endif
}

View file

@ -1,171 +1,171 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint8_t serial2Mode = 0;
Fifo<uint8_t, 512> serial2TxFifo;
DMAFifo<32> serial2RxFifo __DMA (SERIAL_DMA_Stream_RX);
void uart3Setup(unsigned int baudrate, bool dma)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinAFConfig(SERIAL_GPIO, SERIAL_GPIO_PinSource_RX, SERIAL_GPIO_AF);
GPIO_PinAFConfig(SERIAL_GPIO, SERIAL_GPIO_PinSource_TX, SERIAL_GPIO_AF);
GPIO_InitStructure.GPIO_Pin = SERIAL_GPIO_PIN_TX | SERIAL_GPIO_PIN_RX;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(SERIAL_GPIO, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(SERIAL_USART, &USART_InitStructure);
if (dma) {
DMA_InitTypeDef DMA_InitStructure;
serial2RxFifo.clear();
USART_ITConfig(SERIAL_USART, USART_IT_RXNE, DISABLE);
USART_ITConfig(SERIAL_USART, USART_IT_TXE, DISABLE);
DMA_InitStructure.DMA_Channel = SERIAL_DMA_Channel_RX;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&SERIAL_USART->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(serial2RxFifo.buffer());
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = serial2RxFifo.size();
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(SERIAL_DMA_Stream_RX, &DMA_InitStructure);
USART_DMACmd(SERIAL_USART, USART_DMAReq_Rx, ENABLE);
USART_Cmd(SERIAL_USART, ENABLE);
DMA_Cmd(SERIAL_DMA_Stream_RX, ENABLE);
}
else {
USART_Cmd(SERIAL_USART, ENABLE);
USART_ITConfig(SERIAL_USART, USART_IT_RXNE, ENABLE);
USART_ITConfig(SERIAL_USART, USART_IT_TXE, DISABLE);
NVIC_SetPriority(SERIAL_USART_IRQn, 7);
NVIC_EnableIRQ(SERIAL_USART_IRQn);
}
}
void serial2Init(unsigned int mode, unsigned int protocol)
{
serial2Stop();
serial2Mode = mode;
switch (mode) {
case UART_MODE_TELEMETRY_MIRROR:
uart3Setup(FRSKY_SPORT_BAUDRATE, false);
break;
#if !defined(USB_SERIAL) && (defined(DEBUG) || defined(CLI))
case UART_MODE_DEBUG:
uart3Setup(DEBUG_BAUDRATE, false);
break;
#endif
case UART_MODE_TELEMETRY:
if (protocol == PROTOCOL_FRSKY_D_SECONDARY) {
uart3Setup(FRSKY_D_BAUDRATE, true);
}
break;
}
}
void serial2Putc(char c)
{
#if !defined(SIMU)
int n = 0;
while (serial2TxFifo.isFull()) {
delay_ms(1);
if (++n > 100) return;
}
serial2TxFifo.push(c);
USART_ITConfig(SERIAL_USART, USART_IT_TXE, ENABLE);
#endif
}
void serial2SbusInit()
{
uart3Setup(SBUS_BAUDRATE, true);
SERIAL_USART->CR1 |= USART_CR1_M | USART_CR1_PCE ;
}
void serial2Stop()
{
DMA_DeInit(SERIAL_DMA_Stream_RX);
USART_DeInit(SERIAL_USART);
}
uint8_t serial2TracesEnabled()
{
#if defined(DEBUG)
return (serial2Mode == UART_MODE_DEBUG);
#else
return false;
#endif
}
extern "C" void SERIAL_USART_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_SER2);
// Send
if (USART_GetITStatus(SERIAL_USART, USART_IT_TXE) != RESET) {
uint8_t txchar;
if (serial2TxFifo.pop(txchar)) {
/* Write one byte to the transmit data register */
USART_SendData(SERIAL_USART, txchar);
}
else {
USART_ITConfig(SERIAL_USART, USART_IT_TXE, DISABLE);
}
}
#if !defined(USB_SERIAL) && defined(CLI)
// Receive
uint32_t status = SERIAL_USART->SR;
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
uint8_t data = SERIAL_USART->DR;
if (!(status & USART_FLAG_ERRORS)) {
switch (serial2Mode) {
case UART_MODE_DEBUG:
cliRxFifo.push(data);
break;
}
}
status = SERIAL_USART->SR;
}
#endif
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint8_t serial2Mode = 0;
Fifo<uint8_t, 512> serial2TxFifo;
DMAFifo<32> serial2RxFifo __DMA (SERIAL_DMA_Stream_RX);
void uart3Setup(unsigned int baudrate, bool dma)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinAFConfig(SERIAL_GPIO, SERIAL_GPIO_PinSource_RX, SERIAL_GPIO_AF);
GPIO_PinAFConfig(SERIAL_GPIO, SERIAL_GPIO_PinSource_TX, SERIAL_GPIO_AF);
GPIO_InitStructure.GPIO_Pin = SERIAL_GPIO_PIN_TX | SERIAL_GPIO_PIN_RX;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(SERIAL_GPIO, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(SERIAL_USART, &USART_InitStructure);
if (dma) {
DMA_InitTypeDef DMA_InitStructure;
serial2RxFifo.clear();
USART_ITConfig(SERIAL_USART, USART_IT_RXNE, DISABLE);
USART_ITConfig(SERIAL_USART, USART_IT_TXE, DISABLE);
DMA_InitStructure.DMA_Channel = SERIAL_DMA_Channel_RX;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&SERIAL_USART->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(serial2RxFifo.buffer());
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = serial2RxFifo.size();
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(SERIAL_DMA_Stream_RX, &DMA_InitStructure);
USART_DMACmd(SERIAL_USART, USART_DMAReq_Rx, ENABLE);
USART_Cmd(SERIAL_USART, ENABLE);
DMA_Cmd(SERIAL_DMA_Stream_RX, ENABLE);
}
else {
USART_Cmd(SERIAL_USART, ENABLE);
USART_ITConfig(SERIAL_USART, USART_IT_RXNE, ENABLE);
USART_ITConfig(SERIAL_USART, USART_IT_TXE, DISABLE);
NVIC_SetPriority(SERIAL_USART_IRQn, 7);
NVIC_EnableIRQ(SERIAL_USART_IRQn);
}
}
void serial2Init(unsigned int mode, unsigned int protocol)
{
serial2Stop();
serial2Mode = mode;
switch (mode) {
case UART_MODE_TELEMETRY_MIRROR:
uart3Setup(FRSKY_SPORT_BAUDRATE, false);
break;
#if !defined(USB_SERIAL) && (defined(DEBUG) || defined(CLI))
case UART_MODE_DEBUG:
uart3Setup(DEBUG_BAUDRATE, false);
break;
#endif
case UART_MODE_TELEMETRY:
if (protocol == PROTOCOL_FRSKY_D_SECONDARY) {
uart3Setup(FRSKY_D_BAUDRATE, true);
}
break;
}
}
void serial2Putc(char c)
{
#if !defined(SIMU)
int n = 0;
while (serial2TxFifo.isFull()) {
delay_ms(1);
if (++n > 100) return;
}
serial2TxFifo.push(c);
USART_ITConfig(SERIAL_USART, USART_IT_TXE, ENABLE);
#endif
}
void serial2SbusInit()
{
uart3Setup(SBUS_BAUDRATE, true);
SERIAL_USART->CR1 |= USART_CR1_M | USART_CR1_PCE ;
}
void serial2Stop()
{
DMA_DeInit(SERIAL_DMA_Stream_RX);
USART_DeInit(SERIAL_USART);
}
uint8_t serial2TracesEnabled()
{
#if defined(DEBUG)
return (serial2Mode == UART_MODE_DEBUG);
#else
return false;
#endif
}
extern "C" void SERIAL_USART_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_SER2);
// Send
if (USART_GetITStatus(SERIAL_USART, USART_IT_TXE) != RESET) {
uint8_t txchar;
if (serial2TxFifo.pop(txchar)) {
/* Write one byte to the transmit data register */
USART_SendData(SERIAL_USART, txchar);
}
else {
USART_ITConfig(SERIAL_USART, USART_IT_TXE, DISABLE);
}
}
#if !defined(USB_SERIAL) && defined(CLI)
// Receive
uint32_t status = SERIAL_USART->SR;
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
uint8_t data = SERIAL_USART->DR;
if (!(status & USART_FLAG_ERRORS)) {
switch (serial2Mode) {
case UART_MODE_DEBUG:
cliRxFifo.push(data);
break;
}
}
status = SERIAL_USART->SR;
}
#endif
}

View file

@ -1,118 +1,118 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Includes ------------------------------------------------------------------*/
#include "usb_bsp.h"
#include "board.h"
#include "usbd_conf.h"
extern uint32_t SystemCoreClock;
/**
* @brief USB_OTG_BSP_Init
* Initilizes BSP configurations
* @param None
* @retval None
*/
void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(USB_RCC_AHB1Periph_GPIO, ENABLE);
/* Configure DM and DP Pins */
GPIO_InitStructure.GPIO_Pin = USB_GPIO_PIN_DM | USB_GPIO_PIN_DP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(USB_GPIO, &GPIO_InitStructure);
GPIO_PinAFConfig(USB_GPIO, USB_GPIO_PinSource_DM, USB_GPIO_AF);
GPIO_PinAFConfig(USB_GPIO, USB_GPIO_PinSource_DP, USB_GPIO_AF);
/* Configure VBUS Pin */
GPIO_InitStructure.GPIO_Pin = USB_GPIO_PIN_VBUS;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(USB_GPIO, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE) ;
}
void USB_OTG_BSP_Deinit(USB_OTG_CORE_HANDLE *pdev)
{
//nothing to do
}
/**
* @brief USB_OTG_BSP_EnableInterrupt
* Enable USB Global interrupt
* @param None
* @retval None
*/
void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev)
{
NVIC_SetPriority(OTG_FS_IRQn, 11); // Lower priority interrupt
NVIC_EnableIRQ(OTG_FS_IRQn);
}
/**
* @brief USB_OTG_BSP_DisableInterrupt
* Disable USB Global interrupt
* @param None
* @retval None
*/
void USB_OTG_BSP_DisableInterrupt(USB_OTG_CORE_HANDLE *pdev)
{
NVIC_DisableIRQ(OTG_FS_IRQn);
}
/**
* @brief USB_OTG_BSP_uDelay
* This function provides delay time in micro sec
* @param usec : Value of delay required in micro sec
* @retval None
*/
void USB_OTG_BSP_uDelay (const uint32_t usec)
{
delay_us(usec);
}
/**
* @brief USB_OTG_BSP_mDelay
* This function provides delay time in milli sec
* @param msec : Value of delay required in milli sec
* @retval None
*/
void USB_OTG_BSP_mDelay (const uint32_t msec)
{
delay_ms(msec);
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Includes ------------------------------------------------------------------*/
#include "usb_bsp.h"
#include "board.h"
#include "usbd_conf.h"
extern uint32_t SystemCoreClock;
/**
* @brief USB_OTG_BSP_Init
* Initilizes BSP configurations
* @param None
* @retval None
*/
void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(USB_RCC_AHB1Periph_GPIO, ENABLE);
/* Configure DM and DP Pins */
GPIO_InitStructure.GPIO_Pin = USB_GPIO_PIN_DM | USB_GPIO_PIN_DP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(USB_GPIO, &GPIO_InitStructure);
GPIO_PinAFConfig(USB_GPIO, USB_GPIO_PinSource_DM, USB_GPIO_AF);
GPIO_PinAFConfig(USB_GPIO, USB_GPIO_PinSource_DP, USB_GPIO_AF);
/* Configure VBUS Pin */
GPIO_InitStructure.GPIO_Pin = USB_GPIO_PIN_VBUS;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(USB_GPIO, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE) ;
}
void USB_OTG_BSP_Deinit(USB_OTG_CORE_HANDLE *pdev)
{
//nothing to do
}
/**
* @brief USB_OTG_BSP_EnableInterrupt
* Enable USB Global interrupt
* @param None
* @retval None
*/
void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev)
{
NVIC_SetPriority(OTG_FS_IRQn, 11); // Lower priority interrupt
NVIC_EnableIRQ(OTG_FS_IRQn);
}
/**
* @brief USB_OTG_BSP_DisableInterrupt
* Disable USB Global interrupt
* @param None
* @retval None
*/
void USB_OTG_BSP_DisableInterrupt(USB_OTG_CORE_HANDLE *pdev)
{
NVIC_DisableIRQ(OTG_FS_IRQn);
}
/**
* @brief USB_OTG_BSP_uDelay
* This function provides delay time in micro sec
* @param usec : Value of delay required in micro sec
* @retval None
*/
void USB_OTG_BSP_uDelay (const uint32_t usec)
{
delay_us(usec);
}
/**
* @brief USB_OTG_BSP_mDelay
* This function provides delay time in milli sec
* @param msec : Value of delay required in milli sec
* @retval None
*/
void USB_OTG_BSP_mDelay (const uint32_t msec)
{
delay_ms(msec);
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -1,168 +1,168 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _USB_CONF_H_
#define _USB_CONF_H_
#if defined(STM32F4)
#include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h"
#else
#include "STM32F2xx_StdPeriph_Lib_V1.1.0/Libraries/CMSIS/Device/ST/STM32F2xx/Include/stm32f2xx.h"
#endif
/* USB Core and PHY interface configuration.
Tip: To avoid modifying these defines each time you need to change the USB
configuration, you can declare the needed define in your toolchain
compiler preprocessor.
*/
/****************** USB OTG FS PHY CONFIGURATION *******************************
* The USB OTG FS Core supports one on-chip Full Speed PHY.
*
* The USE_EMBEDDED_PHY symbol is defined in the project compiler preprocessor
* when FS core is used.
*******************************************************************************/
#ifndef USE_USB_OTG_FS
#define USE_USB_OTG_FS // USB2.0 Full Speed == 12 Mbit
#endif /* USE_USB_OTG_FS */
#ifdef USE_USB_OTG_FS
#define USB_OTG_FS_CORE
#endif
/*******************************************************************************
* FIFO Size Configuration in Device mode
*
* (i) Receive data FIFO size = RAM for setup packets +
* OUT endpoint control information +
* data OUT packets + miscellaneous
* Space = ONE 32-bits words
* --> RAM for setup packets = 10 spaces
* (n is the nbr of CTRL EPs the device core supports)
* --> OUT EP CTRL info = 1 space
* (one space for status information written to the FIFO along with each
* received packet)
* --> data OUT packets = (Largest Packet Size / 4) + 1 spaces
* (MINIMUM to receive packets)
* --> OR data OUT packets = at least 2*(Largest Packet Size / 4) + 1 spaces
* (if high-bandwidth EP is enabled or multiple isochronous EPs)
* --> miscellaneous = 1 space per OUT EP
* (one space for transfer complete status information also pushed to the
* FIFO with each endpoint's last packet)
*
* (ii)MINIMUM RAM space required for each IN EP Tx FIFO = MAX packet size for
* that particular IN EP. More space allocated in the IN EP Tx FIFO results
* in a better performance on the USB and can hide latencies on the AHB.
*
* (iii) TXn min size = 16 words. (n : Transmit FIFO index)
* (iv) When a TxFIFO is not used, the Configuration should be as follows:
* case 1 : n > m and Txn is not used (n,m : Transmit FIFO indexes)
* --> Txm can use the space allocated for Txn.
* case2 : n < m and Txn is not used (n,m : Transmit FIFO indexes)
* --> Txn should be configured with the minimum space of 16 words
* (v) The FIFO is used optimally when used TxFIFOs are allocated in the top
* of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones.
* (vi) In HS case12 FIFO locations should be reserved for internal DMA registers
* so total FIFO size should be 1012 Only instead of 1024
*******************************************************************************/
/****************** USB OTG FS CONFIGURATION **********************************/
#ifdef USB_OTG_FS_CORE
#define RX_FIFO_FS_SIZE 128
#define TX0_FIFO_FS_SIZE 64
#define TX1_FIFO_FS_SIZE 128
#define TX2_FIFO_FS_SIZE 0
#define TX3_FIFO_FS_SIZE 0
// #define USB_OTG_FS_LOW_PWR_MGMT_SUPPORT
// #define USB_OTG_FS_SOF_OUTPUT_ENABLED
#endif
/****************** USB OTG MISC CONFIGURATION ********************************/
#define VBUS_SENSING_ENABLED
/****************** USB OTG MODE CONFIGURATION ********************************/
//#define USE_HOST_MODE
#define USE_DEVICE_MODE
//#define USE_OTG_MODE
#ifndef USB_OTG_FS_CORE
#ifndef USB_OTG_HS_CORE
#error "USB_OTG_HS_CORE or USB_OTG_FS_CORE should be defined"
#endif
#endif
#ifndef USE_DEVICE_MODE
#ifndef USE_HOST_MODE
#error "USE_DEVICE_MODE or USE_HOST_MODE should be defined"
#endif
#endif
#ifndef USE_USB_OTG_HS
#ifndef USE_USB_OTG_FS
#error "USE_USB_OTG_HS or USE_USB_OTG_FS should be defined"
#endif
#else //USE_USB_OTG_HS
#ifndef USE_ULPI_PHY
#ifndef USE_EMBEDDED_PHY
#error "USE_ULPI_PHY or USE_EMBEDDED_PHY should be defined"
#endif
#endif
#endif
/****************** C Compilers dependant keywords ****************************/
/* In HS mode and when the DMA is used, all variables and data structures dealing
with the DMA during the transaction process should be 4-bytes aligned */
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined (__GNUC__) /* GNU Compiler */
#define __ALIGN_END __attribute__ ((aligned (4)))
#define __ALIGN_BEGIN
#else
#define __ALIGN_END
#if defined (__CC_ARM) /* ARM Compiler */
#define __ALIGN_BEGIN __align(4)
#elif defined (__ICCARM__) /* IAR Compiler */
#define __ALIGN_BEGIN
#elif defined (__TASKING__) /* TASKING Compiler */
#define __ALIGN_BEGIN __align(4)
#endif /* __CC_ARM */
#endif /* __GNUC__ */
#else
#define __ALIGN_BEGIN
#define __ALIGN_END
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
/* __packed keyword used to decrease the data type alignment to 1-byte */
#if !defined(__packed)
#if defined (__CC_ARM) /* ARM Compiler */
#define __packed __packed
#elif defined (__ICCARM__) /* IAR Compiler */
#define __packed __packed
#elif defined ( __GNUC__ ) /* GNU Compiler */
#define __packed __attribute__ ((__packed__))
#elif defined (__TASKING__) /* TASKING Compiler */
#define __packed __unaligned
#endif /* __CC_ARM */
#endif
#endif // _USB_CONF_H_
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _USB_CONF_H_
#define _USB_CONF_H_
#if defined(STM32F4)
#include "STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h"
#else
#include "STM32F2xx_StdPeriph_Lib_V1.1.0/Libraries/CMSIS/Device/ST/STM32F2xx/Include/stm32f2xx.h"
#endif
/* USB Core and PHY interface configuration.
Tip: To avoid modifying these defines each time you need to change the USB
configuration, you can declare the needed define in your toolchain
compiler preprocessor.
*/
/****************** USB OTG FS PHY CONFIGURATION *******************************
* The USB OTG FS Core supports one on-chip Full Speed PHY.
*
* The USE_EMBEDDED_PHY symbol is defined in the project compiler preprocessor
* when FS core is used.
*******************************************************************************/
#ifndef USE_USB_OTG_FS
#define USE_USB_OTG_FS // USB2.0 Full Speed == 12 Mbit
#endif /* USE_USB_OTG_FS */
#ifdef USE_USB_OTG_FS
#define USB_OTG_FS_CORE
#endif
/*******************************************************************************
* FIFO Size Configuration in Device mode
*
* (i) Receive data FIFO size = RAM for setup packets +
* OUT endpoint control information +
* data OUT packets + miscellaneous
* Space = ONE 32-bits words
* --> RAM for setup packets = 10 spaces
* (n is the nbr of CTRL EPs the device core supports)
* --> OUT EP CTRL info = 1 space
* (one space for status information written to the FIFO along with each
* received packet)
* --> data OUT packets = (Largest Packet Size / 4) + 1 spaces
* (MINIMUM to receive packets)
* --> OR data OUT packets = at least 2*(Largest Packet Size / 4) + 1 spaces
* (if high-bandwidth EP is enabled or multiple isochronous EPs)
* --> miscellaneous = 1 space per OUT EP
* (one space for transfer complete status information also pushed to the
* FIFO with each endpoint's last packet)
*
* (ii)MINIMUM RAM space required for each IN EP Tx FIFO = MAX packet size for
* that particular IN EP. More space allocated in the IN EP Tx FIFO results
* in a better performance on the USB and can hide latencies on the AHB.
*
* (iii) TXn min size = 16 words. (n : Transmit FIFO index)
* (iv) When a TxFIFO is not used, the Configuration should be as follows:
* case 1 : n > m and Txn is not used (n,m : Transmit FIFO indexes)
* --> Txm can use the space allocated for Txn.
* case2 : n < m and Txn is not used (n,m : Transmit FIFO indexes)
* --> Txn should be configured with the minimum space of 16 words
* (v) The FIFO is used optimally when used TxFIFOs are allocated in the top
* of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones.
* (vi) In HS case12 FIFO locations should be reserved for internal DMA registers
* so total FIFO size should be 1012 Only instead of 1024
*******************************************************************************/
/****************** USB OTG FS CONFIGURATION **********************************/
#ifdef USB_OTG_FS_CORE
#define RX_FIFO_FS_SIZE 128
#define TX0_FIFO_FS_SIZE 64
#define TX1_FIFO_FS_SIZE 128
#define TX2_FIFO_FS_SIZE 0
#define TX3_FIFO_FS_SIZE 0
// #define USB_OTG_FS_LOW_PWR_MGMT_SUPPORT
// #define USB_OTG_FS_SOF_OUTPUT_ENABLED
#endif
/****************** USB OTG MISC CONFIGURATION ********************************/
#define VBUS_SENSING_ENABLED
/****************** USB OTG MODE CONFIGURATION ********************************/
//#define USE_HOST_MODE
#define USE_DEVICE_MODE
//#define USE_OTG_MODE
#ifndef USB_OTG_FS_CORE
#ifndef USB_OTG_HS_CORE
#error "USB_OTG_HS_CORE or USB_OTG_FS_CORE should be defined"
#endif
#endif
#ifndef USE_DEVICE_MODE
#ifndef USE_HOST_MODE
#error "USE_DEVICE_MODE or USE_HOST_MODE should be defined"
#endif
#endif
#ifndef USE_USB_OTG_HS
#ifndef USE_USB_OTG_FS
#error "USE_USB_OTG_HS or USE_USB_OTG_FS should be defined"
#endif
#else //USE_USB_OTG_HS
#ifndef USE_ULPI_PHY
#ifndef USE_EMBEDDED_PHY
#error "USE_ULPI_PHY or USE_EMBEDDED_PHY should be defined"
#endif
#endif
#endif
/****************** C Compilers dependant keywords ****************************/
/* In HS mode and when the DMA is used, all variables and data structures dealing
with the DMA during the transaction process should be 4-bytes aligned */
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined (__GNUC__) /* GNU Compiler */
#define __ALIGN_END __attribute__ ((aligned (4)))
#define __ALIGN_BEGIN
#else
#define __ALIGN_END
#if defined (__CC_ARM) /* ARM Compiler */
#define __ALIGN_BEGIN __align(4)
#elif defined (__ICCARM__) /* IAR Compiler */
#define __ALIGN_BEGIN
#elif defined (__TASKING__) /* TASKING Compiler */
#define __ALIGN_BEGIN __align(4)
#endif /* __CC_ARM */
#endif /* __GNUC__ */
#else
#define __ALIGN_BEGIN
#define __ALIGN_END
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
/* __packed keyword used to decrease the data type alignment to 1-byte */
#if !defined(__packed)
#if defined (__CC_ARM) /* ARM Compiler */
#define __packed __packed
#elif defined (__ICCARM__) /* IAR Compiler */
#define __packed __packed
#elif defined ( __GNUC__ ) /* GNU Compiler */
#define __packed __attribute__ ((__packed__))
#elif defined (__TASKING__) /* TASKING Compiler */
#define __packed __unaligned
#endif /* __CC_ARM */
#endif
#endif // _USB_CONF_H_
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -1,232 +1,232 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#pragma data_alignment = 4
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
#include "opentx.h"
extern "C" {
/* Includes ------------------------------------------------------------------*/
#include "usb_conf.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* These are external variables imported from CDC core to be used for IN
transfer management. */
extern uint8_t APP_Rx_Buffer []; /* Write CDC received data in this buffer.
These data will be sent over USB IN endpoint
in the CDC core functions. */
extern volatile uint32_t APP_Rx_ptr_in; /* Increment this pointer or roll it back to
start address when writing received data
in the buffer APP_Rx_Buffer. */
extern volatile uint32_t APP_Rx_ptr_out;
/* Private function prototypes -----------------------------------------------*/
static uint16_t VCP_Init (void);
static uint16_t VCP_DeInit (void);
static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len);
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len);
extern "C" const CDC_IF_Prop_TypeDef VCP_fops =
{
VCP_Init,
VCP_DeInit,
VCP_Ctrl,
0,
VCP_DataRx
};
} // extern "C"
bool cdcConnected = false;
/* Private functions ---------------------------------------------------------*/
/**
* @brief VCP_Init
* Initializes the Media on the STM32
* @param None
* @retval Result of the opeartion (USBD_OK in all cases)
*/
static uint16_t VCP_Init(void)
{
cdcConnected = true;
return USBD_OK;
}
/**
* @brief VCP_DeInit
* DeInitializes the Media on the STM32
* @param None
* @retval Result of the opeartion (USBD_OK in all cases)
*/
static uint16_t VCP_DeInit(void)
{
cdcConnected = false;
return USBD_OK;
}
/**
* @brief VCP_Ctrl
* Manage the CDC class requests
* @param Cmd: Command code
* @param Buf: Buffer containing command data (request parameters)
* @param Len: Number of data to be sent (in bytes)
* @retval Result of the opeartion (USBD_OK in all cases)
*/
static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len)
{
switch (Cmd)
{
case SEND_ENCAPSULATED_COMMAND:
/* Not needed for this driver */
break;
case GET_ENCAPSULATED_RESPONSE:
/* Not needed for this driver */
break;
case SET_COMM_FEATURE:
/* Not needed for this driver */
break;
case GET_COMM_FEATURE:
/* Not needed for this driver */
break;
case CLEAR_COMM_FEATURE:
/* Not needed for this driver */
break;
case SET_LINE_CODING:
/* Not needed for this driver */
break;
case GET_LINE_CODING:
/* Not needed for this driver */
break;
case SET_CONTROL_LINE_STATE:
/* Not needed for this driver */
break;
case SEND_BREAK:
/* Not needed for this driver */
break;
default:
break;
}
return USBD_OK;
}
// some debug vars
uint16_t usbWraps = 0;
uint16_t charsWritten = 0;
void usbSerialPutc(uint8_t c)
{
/*
Apparently there is no reliable way to tell if the
virtual serial port is opened or not.
The cdcConnected variable only reports the state
of the physical USB connection.
*/
if (!cdcConnected) return;
uint32_t prim = __get_PRIMASK();
__disable_irq();
uint32_t txDataLen = APP_RX_DATA_SIZE + APP_Rx_ptr_in - APP_Rx_ptr_out;
if (!prim) __enable_irq();
if (txDataLen >= APP_RX_DATA_SIZE) {
txDataLen -= APP_RX_DATA_SIZE;
}
if (txDataLen > (APP_RX_DATA_SIZE - CDC_DATA_MAX_PACKET_SIZE)) return; // buffer is too full, skip this write
++charsWritten;
/*
APP_Rx_Buffer and associated variables must be modified
atomically, because they are used from the interrupt
*/
/* Read PRIMASK register, check interrupt status before you disable them */
/* Returns 0 if they are enabled, or non-zero if disabled */
prim = __get_PRIMASK();
__disable_irq();
APP_Rx_Buffer[APP_Rx_ptr_in++] = c;
if(APP_Rx_ptr_in >= APP_RX_DATA_SIZE)
{
APP_Rx_ptr_in = 0;
++usbWraps;
}
if (!prim) __enable_irq();
}
/**
* @brief VCP_DataRx
* Data received over USB OUT endpoint is available here
*
* @note
* This function will block any OUT packet reception on USB endpoint
* until exiting this function. If you exit this function before transfer
* is complete on CDC interface (ie. using DMA controller) it will result
* in receiving more data while previous ones are still not sent.
*
* @note
* This function is executed inside the USBD_OTG_ISR_Handler() interrupt handler!
* @param Buf: Buffer of data to be received
* @param Len: Number of data received (in bytes)
* @retval Result of the opeartion: USBD_OK if all operations are OK else VCP_FAIL
*/
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)
{
// TODO: try implementing inbound flow control:
// if the cliRxFifo does not have enough free space to receive all
// available characters, return VCP_FAIL. Maybe that will throttle down
// the sender and we will receive the same packet at a later time.
#if defined(CLI)
//copy data to the application FIFO
for (uint32_t i = 0; i < Len; i++)
{
cliRxFifo.push(Buf[i]);
}
#endif
return USBD_OK;
}
// /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#pragma data_alignment = 4
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
#include "opentx.h"
extern "C" {
/* Includes ------------------------------------------------------------------*/
#include "usb_conf.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* These are external variables imported from CDC core to be used for IN
transfer management. */
extern uint8_t APP_Rx_Buffer []; /* Write CDC received data in this buffer.
These data will be sent over USB IN endpoint
in the CDC core functions. */
extern volatile uint32_t APP_Rx_ptr_in; /* Increment this pointer or roll it back to
start address when writing received data
in the buffer APP_Rx_Buffer. */
extern volatile uint32_t APP_Rx_ptr_out;
/* Private function prototypes -----------------------------------------------*/
static uint16_t VCP_Init (void);
static uint16_t VCP_DeInit (void);
static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len);
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len);
extern "C" const CDC_IF_Prop_TypeDef VCP_fops =
{
VCP_Init,
VCP_DeInit,
VCP_Ctrl,
0,
VCP_DataRx
};
} // extern "C"
bool cdcConnected = false;
/* Private functions ---------------------------------------------------------*/
/**
* @brief VCP_Init
* Initializes the Media on the STM32
* @param None
* @retval Result of the opeartion (USBD_OK in all cases)
*/
static uint16_t VCP_Init(void)
{
cdcConnected = true;
return USBD_OK;
}
/**
* @brief VCP_DeInit
* DeInitializes the Media on the STM32
* @param None
* @retval Result of the opeartion (USBD_OK in all cases)
*/
static uint16_t VCP_DeInit(void)
{
cdcConnected = false;
return USBD_OK;
}
/**
* @brief VCP_Ctrl
* Manage the CDC class requests
* @param Cmd: Command code
* @param Buf: Buffer containing command data (request parameters)
* @param Len: Number of data to be sent (in bytes)
* @retval Result of the opeartion (USBD_OK in all cases)
*/
static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len)
{
switch (Cmd)
{
case SEND_ENCAPSULATED_COMMAND:
/* Not needed for this driver */
break;
case GET_ENCAPSULATED_RESPONSE:
/* Not needed for this driver */
break;
case SET_COMM_FEATURE:
/* Not needed for this driver */
break;
case GET_COMM_FEATURE:
/* Not needed for this driver */
break;
case CLEAR_COMM_FEATURE:
/* Not needed for this driver */
break;
case SET_LINE_CODING:
/* Not needed for this driver */
break;
case GET_LINE_CODING:
/* Not needed for this driver */
break;
case SET_CONTROL_LINE_STATE:
/* Not needed for this driver */
break;
case SEND_BREAK:
/* Not needed for this driver */
break;
default:
break;
}
return USBD_OK;
}
// some debug vars
uint16_t usbWraps = 0;
uint16_t charsWritten = 0;
void usbSerialPutc(uint8_t c)
{
/*
Apparently there is no reliable way to tell if the
virtual serial port is opened or not.
The cdcConnected variable only reports the state
of the physical USB connection.
*/
if (!cdcConnected) return;
uint32_t prim = __get_PRIMASK();
__disable_irq();
uint32_t txDataLen = APP_RX_DATA_SIZE + APP_Rx_ptr_in - APP_Rx_ptr_out;
if (!prim) __enable_irq();
if (txDataLen >= APP_RX_DATA_SIZE) {
txDataLen -= APP_RX_DATA_SIZE;
}
if (txDataLen > (APP_RX_DATA_SIZE - CDC_DATA_MAX_PACKET_SIZE)) return; // buffer is too full, skip this write
++charsWritten;
/*
APP_Rx_Buffer and associated variables must be modified
atomically, because they are used from the interrupt
*/
/* Read PRIMASK register, check interrupt status before you disable them */
/* Returns 0 if they are enabled, or non-zero if disabled */
prim = __get_PRIMASK();
__disable_irq();
APP_Rx_Buffer[APP_Rx_ptr_in++] = c;
if(APP_Rx_ptr_in >= APP_RX_DATA_SIZE)
{
APP_Rx_ptr_in = 0;
++usbWraps;
}
if (!prim) __enable_irq();
}
/**
* @brief VCP_DataRx
* Data received over USB OUT endpoint is available here
*
* @note
* This function will block any OUT packet reception on USB endpoint
* until exiting this function. If you exit this function before transfer
* is complete on CDC interface (ie. using DMA controller) it will result
* in receiving more data while previous ones are still not sent.
*
* @note
* This function is executed inside the USBD_OTG_ISR_Handler() interrupt handler!
* @param Buf: Buffer of data to be received
* @param Len: Number of data received (in bytes)
* @retval Result of the opeartion: USBD_OK if all operations are OK else VCP_FAIL
*/
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)
{
// TODO: try implementing inbound flow control:
// if the cliRxFifo does not have enough free space to receive all
// available characters, return VCP_FAIL. Maybe that will throttle down
// the sender and we will receive the same packet at a later time.
#if defined(CLI)
//copy data to the application FIFO
for (uint32_t i = 0; i < Len; i++)
{
cliRxFifo.push(Buf[i]);
}
#endif
return USBD_OK;
}
// /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -18,47 +18,47 @@
* GNU General Public License for more details.
*/
/* Define to prevent recursive inclusion -------------------------------------*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _USBD_CONF_H_
#define _USBD_CONF_H_
/* Includes ------------------------------------------------------------------*/
#include "usb_conf.h"
#define USBD_CFG_MAX_NUM 1
#define USBD_ITF_MAX_NUM 1
#define USB_MAX_STR_DESC_SIZ 64
#define USBD_SELF_POWERED
/* Class Layer Parameter */
#define MSC_IN_EP 0x81
#define MSC_OUT_EP 0x01
#define MSC_MAX_PACKET 64
#define MSC_MEDIA_PACKET 4096
#define HID_IN_EP 0x81
#define HID_OUT_EP 0x01
#define HID_IN_PACKET 11
#define HID_OUT_PACKET 9
#define CDC_IN_EP 0x81 /* EP1 for data IN */
#define CDC_OUT_EP 0x01 /* EP1 for data OUT */
#define CDC_CMD_EP 0x82 /* EP2 for CDC commands */
/* CDC Endpoints parameters: you can fine tune these values depending on the needed baudrates and performance. */
#define CDC_DATA_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */
#define CDC_CMD_PACKET_SZE 8 /* Control Endpoint Packet size */
#define CDC_IN_FRAME_INTERVAL 5 /* Number of frames between IN transfers */
#define APP_RX_DATA_SIZE 512 // USB serial port output buffer. TODO: tune this buffer size /* Total size of IN buffer: APP_RX_DATA_SIZE*8/MAX_BAUDARATE*1000 should be > CDC_IN_FRAME_INTERVAL */
#define APP_FOPS VCP_fops
/* Includes ------------------------------------------------------------------*/
#include "usb_conf.h"
#define USBD_CFG_MAX_NUM 1
#define USBD_ITF_MAX_NUM 1
#define USB_MAX_STR_DESC_SIZ 64
#define USBD_SELF_POWERED
/* Class Layer Parameter */
#define MSC_IN_EP 0x81
#define MSC_OUT_EP 0x01
#define MSC_MAX_PACKET 64
#define MSC_MEDIA_PACKET 4096
#define HID_IN_EP 0x81
#define HID_OUT_EP 0x01
#define HID_IN_PACKET 11
#define HID_OUT_PACKET 9
#define CDC_IN_EP 0x81 /* EP1 for data IN */
#define CDC_OUT_EP 0x01 /* EP1 for data OUT */
#define CDC_CMD_EP 0x82 /* EP2 for CDC commands */
/* CDC Endpoints parameters: you can fine tune these values depending on the needed baudrates and performance. */
#define CDC_DATA_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */
#define CDC_CMD_PACKET_SZE 8 /* Control Endpoint Packet size */
#define CDC_IN_FRAME_INTERVAL 5 /* Number of frames between IN transfers */
#define APP_RX_DATA_SIZE 512 // USB serial port output buffer. TODO: tune this buffer size /* Total size of IN buffer: APP_RX_DATA_SIZE*8/MAX_BAUDARATE*1000 should be > CDC_IN_FRAME_INTERVAL */
#define APP_FOPS VCP_fops
#endif // _USBD_CONF_H_
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -1,239 +1,239 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_desc.h"
#include <string.h>
#include "board.h"
#include "usbd_conf.h"
#include "usbd_core.h"
#include "usbd_req.h"
#include "usb_regs.h"
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_DESC
* @brief USBD descriptors module
* @{
*/
/** @defgroup USBD_DESC_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Defines
* @{
*/
#define USBD_VID 0x0483
#define USBD_LANGID_STRING 0x409
#define USBD_MANUFACTURER_STRING "FrSky"
#define USBD_SERIALNUMBER_FS_STRING "00000000001B"
#if defined(BOOT)
#define USBD_PID 0x5720
#define USBD_PRODUCT_FS_STRING USB_NAME " Bootloader"
#define USBD_CONFIGURATION_FS_STRING "MSC Config"
#define USBD_INTERFACE_FS_STRING "MSC Interface"
#elif defined(USB_JOYSTICK)
#define USBD_PID 0x5710
#define USBD_PRODUCT_FS_STRING USB_NAME " Joystick"
#define USBD_CONFIGURATION_FS_STRING "HID Config"
#define USBD_INTERFACE_FS_STRING "HID Interface"
#elif defined(USB_SERIAL)
#define USBD_PID 0x5740 // do not change, this ID is used by the ST USB driver for Windows
#define USBD_PRODUCT_FS_STRING USB_NAME " Serial Port"
#define USBD_CONFIGURATION_FS_STRING "VSP Config"
#define USBD_INTERFACE_FS_STRING "VSP Interface"
#elif defined(USB_MASS_STORAGE)
#define USBD_PID 0x5720
#define USBD_PRODUCT_FS_STRING USB_NAME " Mass Storage"
#define USBD_CONFIGURATION_FS_STRING "MSC Config"
#define USBD_INTERFACE_FS_STRING "MSC Interface"
#endif
const USBD_DEVICE USR_desc =
{
USBD_USR_DeviceDescriptor,
USBD_USR_LangIDStrDescriptor,
USBD_USR_ManufacturerStrDescriptor,
USBD_USR_ProductStrDescriptor,
USBD_USR_SerialStrDescriptor,
USBD_USR_ConfigStrDescriptor,
USBD_USR_InterfaceStrDescriptor,
};
/* USB Standard Device Descriptor */
__ALIGN_BEGIN const uint8_t USBD_DeviceDesc[USB_SIZ_DEVICE_DESC] __ALIGN_END =
{
USB_SIZ_DEVICE_DESC, /*bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x02,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
USB_OTG_MAX_EP0_SIZE, /*bMaxPacketSize*/
LOBYTE(USBD_VID), /*idVendor*/
HIBYTE(USBD_VID), /*idVendor*/
LOBYTE(USBD_PID), /*idVendor*/
HIBYTE(USBD_PID), /*idVendor*/
0x00, /*bcdDevice rel. 2.00*/
0x02,
USBD_IDX_MFC_STR, /*Index of manufacturer string*/
USBD_IDX_PRODUCT_STR, /*Index of product string*/
USBD_IDX_SERIAL_STR, /*Index of serial number string*/
USBD_CFG_MAX_NUM /*bNumConfigurations*/
}; /* USB_DeviceDescriptor */
/* USB Standard Device Descriptor */
__ALIGN_BEGIN const uint8_t USBD_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
0x40,
0x01,
0x00,
};
/* USB Standard Device Descriptor */
__ALIGN_BEGIN const uint8_t USBD_LangIDDesc[USB_SIZ_STRING_LANGID] __ALIGN_END =
{
USB_SIZ_STRING_LANGID,
USB_DESC_TYPE_STRING,
LOBYTE(USBD_LANGID_STRING),
HIBYTE(USBD_LANGID_STRING),
};
__ALIGN_BEGIN uint8_t USBD_StrDesc[USB_MAX_STR_DESC_SIZ] __ALIGN_END ; // modified by OpenTX
/*
* @brief USBD_USR_DeviceDescriptor
* return the device descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length)
{
*length = sizeof(USBD_DeviceDesc);
memcpy(USBD_StrDesc, USBD_DeviceDesc, *length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_LangIDStrDescriptor
* return the LangID string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_LangIDStrDescriptor( uint8_t speed , uint16_t *length)
{
*length = sizeof(USBD_LangIDDesc);
memcpy(USBD_StrDesc, USBD_LangIDDesc, *length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_ProductStrDescriptor
* return the product string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_ProductStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t*)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_ManufacturerStrDescriptor
* return the manufacturer string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_ManufacturerStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t*)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_SerialStrDescriptor
* return the serial number string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_SerialStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t*)USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_ConfigStrDescriptor
* return the configuration string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_ConfigStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_InterfaceStrDescriptor
* return the interface string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_InterfaceStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t*)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_desc.h"
#include <string.h>
#include "board.h"
#include "usbd_conf.h"
#include "usbd_core.h"
#include "usbd_req.h"
#include "usb_regs.h"
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_DESC
* @brief USBD descriptors module
* @{
*/
/** @defgroup USBD_DESC_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Private_Defines
* @{
*/
#define USBD_VID 0x0483
#define USBD_LANGID_STRING 0x409
#define USBD_MANUFACTURER_STRING "FrSky"
#define USBD_SERIALNUMBER_FS_STRING "00000000001B"
#if defined(BOOT)
#define USBD_PID 0x5720
#define USBD_PRODUCT_FS_STRING USB_NAME " Bootloader"
#define USBD_CONFIGURATION_FS_STRING "MSC Config"
#define USBD_INTERFACE_FS_STRING "MSC Interface"
#elif defined(USB_JOYSTICK)
#define USBD_PID 0x5710
#define USBD_PRODUCT_FS_STRING USB_NAME " Joystick"
#define USBD_CONFIGURATION_FS_STRING "HID Config"
#define USBD_INTERFACE_FS_STRING "HID Interface"
#elif defined(USB_SERIAL)
#define USBD_PID 0x5740 // do not change, this ID is used by the ST USB driver for Windows
#define USBD_PRODUCT_FS_STRING USB_NAME " Serial Port"
#define USBD_CONFIGURATION_FS_STRING "VSP Config"
#define USBD_INTERFACE_FS_STRING "VSP Interface"
#elif defined(USB_MASS_STORAGE)
#define USBD_PID 0x5720
#define USBD_PRODUCT_FS_STRING USB_NAME " Mass Storage"
#define USBD_CONFIGURATION_FS_STRING "MSC Config"
#define USBD_INTERFACE_FS_STRING "MSC Interface"
#endif
const USBD_DEVICE USR_desc =
{
USBD_USR_DeviceDescriptor,
USBD_USR_LangIDStrDescriptor,
USBD_USR_ManufacturerStrDescriptor,
USBD_USR_ProductStrDescriptor,
USBD_USR_SerialStrDescriptor,
USBD_USR_ConfigStrDescriptor,
USBD_USR_InterfaceStrDescriptor,
};
/* USB Standard Device Descriptor */
__ALIGN_BEGIN const uint8_t USBD_DeviceDesc[USB_SIZ_DEVICE_DESC] __ALIGN_END =
{
USB_SIZ_DEVICE_DESC, /*bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x02,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
USB_OTG_MAX_EP0_SIZE, /*bMaxPacketSize*/
LOBYTE(USBD_VID), /*idVendor*/
HIBYTE(USBD_VID), /*idVendor*/
LOBYTE(USBD_PID), /*idVendor*/
HIBYTE(USBD_PID), /*idVendor*/
0x00, /*bcdDevice rel. 2.00*/
0x02,
USBD_IDX_MFC_STR, /*Index of manufacturer string*/
USBD_IDX_PRODUCT_STR, /*Index of product string*/
USBD_IDX_SERIAL_STR, /*Index of serial number string*/
USBD_CFG_MAX_NUM /*bNumConfigurations*/
}; /* USB_DeviceDescriptor */
/* USB Standard Device Descriptor */
__ALIGN_BEGIN const uint8_t USBD_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
0x40,
0x01,
0x00,
};
/* USB Standard Device Descriptor */
__ALIGN_BEGIN const uint8_t USBD_LangIDDesc[USB_SIZ_STRING_LANGID] __ALIGN_END =
{
USB_SIZ_STRING_LANGID,
USB_DESC_TYPE_STRING,
LOBYTE(USBD_LANGID_STRING),
HIBYTE(USBD_LANGID_STRING),
};
__ALIGN_BEGIN uint8_t USBD_StrDesc[USB_MAX_STR_DESC_SIZ] __ALIGN_END ; // modified by OpenTX
/*
* @brief USBD_USR_DeviceDescriptor
* return the device descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length)
{
*length = sizeof(USBD_DeviceDesc);
memcpy(USBD_StrDesc, USBD_DeviceDesc, *length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_LangIDStrDescriptor
* return the LangID string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_LangIDStrDescriptor( uint8_t speed , uint16_t *length)
{
*length = sizeof(USBD_LangIDDesc);
memcpy(USBD_StrDesc, USBD_LangIDDesc, *length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_ProductStrDescriptor
* return the product string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_ProductStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t*)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_ManufacturerStrDescriptor
* return the manufacturer string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_ManufacturerStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t*)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_SerialStrDescriptor
* return the serial number string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_SerialStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t*)USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_ConfigStrDescriptor
* return the configuration string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_ConfigStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief USBD_USR_InterfaceStrDescriptor
* return the interface string descriptor
* @param speed : current device speed
* @param length : pointer to data length variable
* @retval pointer to descriptor buffer
*/
uint8_t * USBD_USR_InterfaceStrDescriptor( uint8_t speed , uint16_t *length)
{
USBD_GetString ((uint8_t*)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -18,97 +18,97 @@
* GNU General Public License for more details.
*/
/* Define to prevent recursive inclusion -------------------------------------*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _USBD_DESC_H_
#define _USBD_DESC_H_
/* Includes ------------------------------------------------------------------*/
#include "usb_core.h"
#include "usbd_def.h"
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USB_DESC
* @brief general defines for the usb device library file
* @{
*/
/** @defgroup USB_DESC_Exported_Defines
* @{
*/
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
#define USB_STRING_DESCRIPTOR_TYPE 0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
#define USB_SIZ_DEVICE_DESC 18
#define USB_SIZ_STRING_LANGID 4
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_Variables
* @{
*/
extern const uint8_t USBD_DeviceDesc [USB_SIZ_DEVICE_DESC];
extern uint8_t USBD_StrDesc[USB_MAX_STR_DESC_SIZ];
extern const uint8_t USBD_OtherSpeedCfgDesc[USB_LEN_CFG_DESC];
extern const uint8_t USBD_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC];
extern const uint8_t USBD_LangIDDesc[USB_SIZ_STRING_LANGID];
extern const USBD_DEVICE USR_desc;
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_FunctionsPrototype
* @{
*/
uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_LangIDStrDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_ManufacturerStrDescriptor ( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_ProductStrDescriptor ( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_SerialStrDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_ConfigStrDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_InterfaceStrDescriptor( uint8_t speed , uint16_t *length);
#ifdef USB_SUPPORT_USER_STRING_DESC
uint8_t * USBD_USR_USRStringDesc (uint8_t speed, uint8_t idx , uint16_t *length);
#endif /* USB_SUPPORT_USER_STRING_DESC */
/**
* @}
*/
/* Includes ------------------------------------------------------------------*/
#include "usb_core.h"
#include "usbd_def.h"
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USB_DESC
* @brief general defines for the usb device library file
* @{
*/
/** @defgroup USB_DESC_Exported_Defines
* @{
*/
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
#define USB_STRING_DESCRIPTOR_TYPE 0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
#define USB_SIZ_DEVICE_DESC 18
#define USB_SIZ_STRING_LANGID 4
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_Variables
* @{
*/
extern const uint8_t USBD_DeviceDesc [USB_SIZ_DEVICE_DESC];
extern uint8_t USBD_StrDesc[USB_MAX_STR_DESC_SIZ];
extern const uint8_t USBD_OtherSpeedCfgDesc[USB_LEN_CFG_DESC];
extern const uint8_t USBD_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC];
extern const uint8_t USBD_LangIDDesc[USB_SIZ_STRING_LANGID];
extern const USBD_DEVICE USR_desc;
/**
* @}
*/
/** @defgroup USBD_DESC_Exported_FunctionsPrototype
* @{
*/
uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_LangIDStrDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_ManufacturerStrDescriptor ( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_ProductStrDescriptor ( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_SerialStrDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_ConfigStrDescriptor( uint8_t speed , uint16_t *length);
uint8_t * USBD_USR_InterfaceStrDescriptor( uint8_t speed , uint16_t *length);
#ifdef USB_SUPPORT_USER_STRING_DESC
uint8_t * USBD_USR_USRStringDesc (uint8_t speed, uint8_t idx , uint16_t *length);
#endif /* USB_SUPPORT_USER_STRING_DESC */
/**
* @}
*/
#endif // _USBD_DESC_H_
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -1,455 +1,455 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_desc.h"
#include "usbd_hid_core.h"
#include "usbd_req.h"
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_HID
* @brief usbd core module
* @{
*/
/** @defgroup USBD_HID_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_HID_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_HID_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_HID_Private_FunctionPrototypes
* @{
*/
static uint8_t USBD_HID_Init (void *pdev,
uint8_t cfgidx);
static uint8_t USBD_HID_DeInit (void *pdev,
uint8_t cfgidx);
static uint8_t USBD_HID_Setup (void *pdev,
USB_SETUP_REQ *req);
static const uint8_t *USBD_HID_GetCfgDesc (uint8_t speed, uint16_t *length);
static uint8_t USBD_HID_DataIn (void *pdev, uint8_t epnum);
/**
* @}
*/
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
/*
This USB HID endpoint report description defines a device with:
* 24 digital buttons
* 8 analog axes with 8bit resolution
Repot packet described as C struct is:
struct {
uint8_t buttons1; //bit 0 - button 1, bit 1 - button 2, ..., mapped to channels 9-16, on if channel > 0
uint8_t buttons2; // mapped to channels 17-24, on if channel > 0
uint8_t buttons3; // mapped to channels 25-32, on if channel > 0
uint8_t X; //analog value, mapped to channel 1
uint8_t Y; //analog value, mapped to channel 2
uint8_t Z; //analog value, mapped to channel 3
uint8_t Rx; //analog value, mapped to channel 4
uint8_t Ry //analog value, mapped to channel 5
uint8_t Rz; //analog value, mapped to channel 6
uint8_t S1; //analog value, mapped to channel 7
uint8_t S2; //analog value, mapped to channel 8
}
*/
__ALIGN_BEGIN static const uint8_t HID_JOYSTICK_ReportDesc[] __ALIGN_END =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x18, // USAGE_MAXIMUM (Button 24)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x18, // REPORT_COUNT (24)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x32, // USAGE (Z)
0x09, 0x33, // USAGE (Rx)
0x09, 0x34, // USAGE (Ry)
0x09, 0x35, // USAGE (Rz)
0x09, 0x36, // USAGE (Slider)
0x09, 0x36, // USAGE (Slider)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
/** @defgroup USBD_HID_Private_Variables
* @{
*/
const USBD_Class_cb_TypeDef USBD_HID_cb =
{
USBD_HID_Init,
USBD_HID_DeInit,
USBD_HID_Setup,
NULL, /*EP0_TxSent*/
NULL, /*EP0_RxReady*/
USBD_HID_DataIn, /*DataIn*/
NULL, /*DataOut*/
NULL, /*SOF */
NULL,
NULL,
USBD_HID_GetCfgDesc,
#ifdef USB_OTG_HS_CORE
USBD_HID_GetCfgDesc, /* use same config as per FS */
#endif
};
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN static uint32_t USBD_HID_AltSet __ALIGN_END = 0;
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN static uint32_t USBD_HID_Protocol __ALIGN_END = 0;
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN static uint32_t USBD_HID_IdleState __ALIGN_END = 0;
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
/* USB HID device Configuration Descriptor */
__ALIGN_BEGIN static const uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuration Descriptor size */
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
USB_HID_CONFIG_DESC_SIZ,
/* wTotalLength: Bytes returned */
0x00,
0x01, /*bNumInterfaces: 1 interface*/
0x01, /*bConfigurationValue: Configuration value*/
0x00, /*iConfiguration: Index of string descriptor describing
the configuration*/
0xE0, /*bmAttributes: bus powered and Support Remote Wake-up */
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
/************** Descriptor of Joystick Mouse interface ****************/
/* 09 */
0x09, /*bLength: Interface Descriptor size*/
USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/
0x00, /*bInterfaceNumber: Number of Interface*/
0x00, /*bAlternateSetting: Alternate setting*/
0x01, /*bNumEndpoints*/
0x03, /*bInterfaceClass: HID*/
0x00 /*0x01*/, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
0x00 /*0x02*/, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
0, /*iInterface: Index of string descriptor*/
/******************** Descriptor of Joystick Mouse HID ********************/
/* 18 */
0x09, /*bLength: HID Descriptor size*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
0x11, /*bcdHID: HID Class Spec release number*/
0x01,
0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/
sizeof(HID_JOYSTICK_ReportDesc),/*wItemLength: Total length of Report descriptor*/
0x00,
/******************** Descriptor of Mouse endpoint ********************/
/* 27 */
0x07, /*bLength: Endpoint Descriptor size*/
USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
HID_IN_EP, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/
HID_IN_PACKET, /*wMaxPacketSize: 4 Byte max */
0x00,
0x0A, /*bInterval: Polling Interval (10 ms)*/
/* 34 */
} ;
static uint8_t ReportSent;
/**
* @}
*/
/** @defgroup USBD_HID_Private_Functions
* @{
*/
/**
* @brief USBD_HID_Init
* Initialize the HID interface
* @param pdev: device instance
* @param cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_HID_Init (void *pdev,
uint8_t cfgidx)
{
/* Open EP IN */
DCD_EP_Open(pdev,
HID_IN_EP,
HID_IN_PACKET,
USB_OTG_EP_INT);
/* Open EP OUT */
DCD_EP_Open(pdev,
HID_OUT_EP,
HID_OUT_PACKET,
USB_OTG_EP_INT);
ReportSent = 1;
return USBD_OK;
}
/**
* @brief USBD_HID_Init
* DeInitialize the HID layer
* @param pdev: device instance
* @param cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_HID_DeInit (void *pdev,
uint8_t cfgidx)
{
/* Close HID EPs */
DCD_EP_Close (pdev , HID_IN_EP);
DCD_EP_Close (pdev , HID_OUT_EP);
ReportSent = 1;
return USBD_OK;
}
/**
* @brief USBD_HID_Setup
* Handle the HID specific requests
* @param pdev: instance
* @param req: usb requests
* @retval status
*/
static uint8_t USBD_HID_Setup (void *pdev,
USB_SETUP_REQ *req)
{
uint16_t len = 0;
const uint8_t *pbuf = NULL;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS :
switch (req->bRequest)
{
case HID_REQ_SET_PROTOCOL:
USBD_HID_Protocol = (uint8_t)(req->wValue);
break;
case HID_REQ_GET_PROTOCOL:
USBD_CtlSendData (pdev,
(uint8_t *)&USBD_HID_Protocol,
1);
break;
case HID_REQ_SET_IDLE:
USBD_HID_IdleState = (uint8_t)(req->wValue >> 8);
break;
case HID_REQ_GET_IDLE:
USBD_CtlSendData (pdev,
(uint8_t *)&USBD_HID_IdleState,
1);
break;
default:
USBD_CtlError (pdev, req);
return USBD_FAIL;
}
break;
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_DESCRIPTOR:
if( req->wValue >> 8 == HID_REPORT_DESC)
{
len = MIN(sizeof(HID_JOYSTICK_ReportDesc) , req->wLength);
pbuf = HID_JOYSTICK_ReportDesc; // wiiccReportDescriptor; //
}
else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
{
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
pbuf = USBD_HID_Desc;
#else
pbuf = USBD_HID_CfgDesc + 0x12;
#endif
len = MIN(USB_HID_DESC_SIZ , req->wLength);
}
USBD_CtlSendData (pdev,
pbuf,
len);
break;
case USB_REQ_GET_INTERFACE :
USBD_CtlSendData (pdev,
(uint8_t *)&USBD_HID_AltSet,
1);
break;
case USB_REQ_SET_INTERFACE :
USBD_HID_AltSet = (uint8_t)(req->wValue);
break;
}
}
return USBD_OK;
}
/**
* @brief USBD_HID_SendReport
* Send HID Report if TX buffer is free and USB device is configured.
* @param pdev: device instance
* @param buff: pointer to report, if this parameter is NULL then function just test if new buffer can be sent
* @retval status
*/
uint8_t USBD_HID_SendReport(USB_OTG_CORE_HANDLE *pdev, uint8_t * report, uint16_t len)
{
if (pdev->dev.device_status == USB_OTG_CONFIGURED) {
if (ReportSent) {
if (report) {
ReportSent = 0;
DCD_EP_Tx (pdev, HID_IN_EP, report, len);
}
return USBD_OK;
}
}
return USBD_FAIL;
}
/**
* @brief USBD_HID_GetCfgDesc
* return configuration descriptor
* @param speed : current device speed
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
static const uint8_t *USBD_HID_GetCfgDesc (uint8_t speed, uint16_t *length)
{
*length = sizeof (USBD_HID_CfgDesc);
return USBD_HID_CfgDesc;
}
/**
* @brief USBD_HID_DataIn
* handle data IN Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
This function is called when buffer has been sent over the USB.
The TX buffer is now empty and can be filled with new data.
*/
static uint8_t USBD_HID_DataIn (void *pdev,
uint8_t epnum)
{
ReportSent = 1;
/* Ensure that the FIFO is empty before a new transfer, this condition could
be caused by a new transfer before the end of the previous transfer */
DCD_EP_Flush(pdev, HID_IN_EP);
return USBD_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_desc.h"
#include "usbd_hid_core.h"
#include "usbd_req.h"
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_HID
* @brief usbd core module
* @{
*/
/** @defgroup USBD_HID_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_HID_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_HID_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_HID_Private_FunctionPrototypes
* @{
*/
static uint8_t USBD_HID_Init (void *pdev,
uint8_t cfgidx);
static uint8_t USBD_HID_DeInit (void *pdev,
uint8_t cfgidx);
static uint8_t USBD_HID_Setup (void *pdev,
USB_SETUP_REQ *req);
static const uint8_t *USBD_HID_GetCfgDesc (uint8_t speed, uint16_t *length);
static uint8_t USBD_HID_DataIn (void *pdev, uint8_t epnum);
/**
* @}
*/
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
/*
This USB HID endpoint report description defines a device with:
* 24 digital buttons
* 8 analog axes with 8bit resolution
Repot packet described as C struct is:
struct {
uint8_t buttons1; //bit 0 - button 1, bit 1 - button 2, ..., mapped to channels 9-16, on if channel > 0
uint8_t buttons2; // mapped to channels 17-24, on if channel > 0
uint8_t buttons3; // mapped to channels 25-32, on if channel > 0
uint8_t X; //analog value, mapped to channel 1
uint8_t Y; //analog value, mapped to channel 2
uint8_t Z; //analog value, mapped to channel 3
uint8_t Rx; //analog value, mapped to channel 4
uint8_t Ry //analog value, mapped to channel 5
uint8_t Rz; //analog value, mapped to channel 6
uint8_t S1; //analog value, mapped to channel 7
uint8_t S2; //analog value, mapped to channel 8
}
*/
__ALIGN_BEGIN static const uint8_t HID_JOYSTICK_ReportDesc[] __ALIGN_END =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x18, // USAGE_MAXIMUM (Button 24)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x18, // REPORT_COUNT (24)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x32, // USAGE (Z)
0x09, 0x33, // USAGE (Rx)
0x09, 0x34, // USAGE (Ry)
0x09, 0x35, // USAGE (Rz)
0x09, 0x36, // USAGE (Slider)
0x09, 0x36, // USAGE (Slider)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
/** @defgroup USBD_HID_Private_Variables
* @{
*/
const USBD_Class_cb_TypeDef USBD_HID_cb =
{
USBD_HID_Init,
USBD_HID_DeInit,
USBD_HID_Setup,
NULL, /*EP0_TxSent*/
NULL, /*EP0_RxReady*/
USBD_HID_DataIn, /*DataIn*/
NULL, /*DataOut*/
NULL, /*SOF */
NULL,
NULL,
USBD_HID_GetCfgDesc,
#ifdef USB_OTG_HS_CORE
USBD_HID_GetCfgDesc, /* use same config as per FS */
#endif
};
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN static uint32_t USBD_HID_AltSet __ALIGN_END = 0;
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN static uint32_t USBD_HID_Protocol __ALIGN_END = 0;
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN static uint32_t USBD_HID_IdleState __ALIGN_END = 0;
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
/* USB HID device Configuration Descriptor */
__ALIGN_BEGIN static const uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuration Descriptor size */
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
USB_HID_CONFIG_DESC_SIZ,
/* wTotalLength: Bytes returned */
0x00,
0x01, /*bNumInterfaces: 1 interface*/
0x01, /*bConfigurationValue: Configuration value*/
0x00, /*iConfiguration: Index of string descriptor describing
the configuration*/
0xE0, /*bmAttributes: bus powered and Support Remote Wake-up */
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
/************** Descriptor of Joystick Mouse interface ****************/
/* 09 */
0x09, /*bLength: Interface Descriptor size*/
USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/
0x00, /*bInterfaceNumber: Number of Interface*/
0x00, /*bAlternateSetting: Alternate setting*/
0x01, /*bNumEndpoints*/
0x03, /*bInterfaceClass: HID*/
0x00 /*0x01*/, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
0x00 /*0x02*/, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
0, /*iInterface: Index of string descriptor*/
/******************** Descriptor of Joystick Mouse HID ********************/
/* 18 */
0x09, /*bLength: HID Descriptor size*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
0x11, /*bcdHID: HID Class Spec release number*/
0x01,
0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/
sizeof(HID_JOYSTICK_ReportDesc),/*wItemLength: Total length of Report descriptor*/
0x00,
/******************** Descriptor of Mouse endpoint ********************/
/* 27 */
0x07, /*bLength: Endpoint Descriptor size*/
USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
HID_IN_EP, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/
HID_IN_PACKET, /*wMaxPacketSize: 4 Byte max */
0x00,
0x0A, /*bInterval: Polling Interval (10 ms)*/
/* 34 */
} ;
static uint8_t ReportSent;
/**
* @}
*/
/** @defgroup USBD_HID_Private_Functions
* @{
*/
/**
* @brief USBD_HID_Init
* Initialize the HID interface
* @param pdev: device instance
* @param cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_HID_Init (void *pdev,
uint8_t cfgidx)
{
/* Open EP IN */
DCD_EP_Open(pdev,
HID_IN_EP,
HID_IN_PACKET,
USB_OTG_EP_INT);
/* Open EP OUT */
DCD_EP_Open(pdev,
HID_OUT_EP,
HID_OUT_PACKET,
USB_OTG_EP_INT);
ReportSent = 1;
return USBD_OK;
}
/**
* @brief USBD_HID_Init
* DeInitialize the HID layer
* @param pdev: device instance
* @param cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_HID_DeInit (void *pdev,
uint8_t cfgidx)
{
/* Close HID EPs */
DCD_EP_Close (pdev , HID_IN_EP);
DCD_EP_Close (pdev , HID_OUT_EP);
ReportSent = 1;
return USBD_OK;
}
/**
* @brief USBD_HID_Setup
* Handle the HID specific requests
* @param pdev: instance
* @param req: usb requests
* @retval status
*/
static uint8_t USBD_HID_Setup (void *pdev,
USB_SETUP_REQ *req)
{
uint16_t len = 0;
const uint8_t *pbuf = NULL;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS :
switch (req->bRequest)
{
case HID_REQ_SET_PROTOCOL:
USBD_HID_Protocol = (uint8_t)(req->wValue);
break;
case HID_REQ_GET_PROTOCOL:
USBD_CtlSendData (pdev,
(uint8_t *)&USBD_HID_Protocol,
1);
break;
case HID_REQ_SET_IDLE:
USBD_HID_IdleState = (uint8_t)(req->wValue >> 8);
break;
case HID_REQ_GET_IDLE:
USBD_CtlSendData (pdev,
(uint8_t *)&USBD_HID_IdleState,
1);
break;
default:
USBD_CtlError (pdev, req);
return USBD_FAIL;
}
break;
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_DESCRIPTOR:
if( req->wValue >> 8 == HID_REPORT_DESC)
{
len = MIN(sizeof(HID_JOYSTICK_ReportDesc) , req->wLength);
pbuf = HID_JOYSTICK_ReportDesc; // wiiccReportDescriptor; //
}
else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
{
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
pbuf = USBD_HID_Desc;
#else
pbuf = USBD_HID_CfgDesc + 0x12;
#endif
len = MIN(USB_HID_DESC_SIZ , req->wLength);
}
USBD_CtlSendData (pdev,
pbuf,
len);
break;
case USB_REQ_GET_INTERFACE :
USBD_CtlSendData (pdev,
(uint8_t *)&USBD_HID_AltSet,
1);
break;
case USB_REQ_SET_INTERFACE :
USBD_HID_AltSet = (uint8_t)(req->wValue);
break;
}
}
return USBD_OK;
}
/**
* @brief USBD_HID_SendReport
* Send HID Report if TX buffer is free and USB device is configured.
* @param pdev: device instance
* @param buff: pointer to report, if this parameter is NULL then function just test if new buffer can be sent
* @retval status
*/
uint8_t USBD_HID_SendReport(USB_OTG_CORE_HANDLE *pdev, uint8_t * report, uint16_t len)
{
if (pdev->dev.device_status == USB_OTG_CONFIGURED) {
if (ReportSent) {
if (report) {
ReportSent = 0;
DCD_EP_Tx (pdev, HID_IN_EP, report, len);
}
return USBD_OK;
}
}
return USBD_FAIL;
}
/**
* @brief USBD_HID_GetCfgDesc
* return configuration descriptor
* @param speed : current device speed
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
static const uint8_t *USBD_HID_GetCfgDesc (uint8_t speed, uint16_t *length)
{
*length = sizeof (USBD_HID_CfgDesc);
return USBD_HID_CfgDesc;
}
/**
* @brief USBD_HID_DataIn
* handle data IN Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
This function is called when buffer has been sent over the USB.
The TX buffer is now empty and can be filled with new data.
*/
static uint8_t USBD_HID_DataIn (void *pdev,
uint8_t epnum)
{
ReportSent = 1;
/* Ensure that the FIFO is empty before a new transfer, this condition could
be caused by a new transfer before the end of the previous transfer */
DCD_EP_Flush(pdev, HID_IN_EP);
return USBD_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load diff

View file

@ -1,122 +1,122 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Includes ------------------------------------------------------------------*/
#include "opentx.h"
extern "C" {
#include "usbd_usr.h"
/* Points to the DEVICE_PROP structure of current device */
/* The purpose of this register is to speed up the execution */
const USBD_Usr_cb_TypeDef USR_cb =
{
USBD_USR_Init,
USBD_USR_DeviceReset,
USBD_USR_DeviceConfigured,
USBD_USR_DeviceSuspended,
USBD_USR_DeviceResumed,
USBD_USR_DeviceConnected,
USBD_USR_DeviceDisconnected,
};
}
/**
* @brief Whatever the user application needs to do when USB is initialised
* @param None
* @retval None
*/
void USBD_USR_Init(void)
{
}
/**
* @brief Displays the message on LCD on device reset event
* @param speed : device speed
* @retval None
*/
void USBD_USR_DeviceReset (uint8_t speed)
{
}
/**
* @brief Displays the message on LCD on device config event
* @param None
* @retval Staus
*/
void USBD_USR_DeviceConfigured (void)
{
}
/**
* @brief Displays the message on LCD on device suspend event
* @param None
* @retval None
*/
void USBD_USR_DeviceSuspended(void)
{
}
/**
* @brief Displays the message on LCD on device resume event
* @param None
* @retval None
*/
void USBD_USR_DeviceResumed(void)
{
}
/**
* @brief USBD_USR_DeviceConnected
* Displays the message on LCD on device connection Event
* @param None
* @retval Staus
*/
void USBD_USR_DeviceConnected (void)
{
}
/**
* @brief USBD_USR_DeviceDisonnected
* Displays the message on LCD on device disconnection Event
* @param None
* @retval Staus
*/
void USBD_USR_DeviceDisconnected (void)
{
#if !defined(BOOT) && defined(USB_MASS_STORAGE) && defined(EEPROM)
// TODO is it really needed if we didn't write the EEPROM?
NVIC_SystemReset();
#endif
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Includes ------------------------------------------------------------------*/
#include "opentx.h"
extern "C" {
#include "usbd_usr.h"
/* Points to the DEVICE_PROP structure of current device */
/* The purpose of this register is to speed up the execution */
const USBD_Usr_cb_TypeDef USR_cb =
{
USBD_USR_Init,
USBD_USR_DeviceReset,
USBD_USR_DeviceConfigured,
USBD_USR_DeviceSuspended,
USBD_USR_DeviceResumed,
USBD_USR_DeviceConnected,
USBD_USR_DeviceDisconnected,
};
}
/**
* @brief Whatever the user application needs to do when USB is initialised
* @param None
* @retval None
*/
void USBD_USR_Init(void)
{
}
/**
* @brief Displays the message on LCD on device reset event
* @param speed : device speed
* @retval None
*/
void USBD_USR_DeviceReset (uint8_t speed)
{
}
/**
* @brief Displays the message on LCD on device config event
* @param None
* @retval Staus
*/
void USBD_USR_DeviceConfigured (void)
{
}
/**
* @brief Displays the message on LCD on device suspend event
* @param None
* @retval None
*/
void USBD_USR_DeviceSuspended(void)
{
}
/**
* @brief Displays the message on LCD on device resume event
* @param None
* @retval None
*/
void USBD_USR_DeviceResumed(void)
{
}
/**
* @brief USBD_USR_DeviceConnected
* Displays the message on LCD on device connection Event
* @param None
* @retval Staus
*/
void USBD_USR_DeviceConnected (void)
{
}
/**
* @brief USBD_USR_DeviceDisonnected
* Displays the message on LCD on device disconnection Event
* @param None
* @retval Staus
*/
void USBD_USR_DeviceDisconnected (void)
{
#if !defined(BOOT) && defined(USB_MASS_STORAGE) && defined(EEPROM)
// TODO is it really needed if we didn't write the EEPROM?
NVIC_SystemReset();
#endif
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -1,171 +1,171 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BOARD_GRUVIN9X_H_
#define _BOARD_GRUVIN9X_H_
#include "../common/avr/board_avr.h"
// Board driver
void boardInit(void);
#define boardOff() pwrOff()
// Keys
#define KEYS_GPIO_REG_MENU pinl
#define KEYS_GPIO_PIN_MENU (1<<4)
#define KEYS_GPIO_REG_EXIT pinl
#define KEYS_GPIO_PIN_EXIT (1<<5)
#define KEYS_GPIO_REG_RIGHT pinl
#define KEYS_GPIO_PIN_RIGHT (1<<2)
#define KEYS_GPIO_REG_LEFT pinl
#define KEYS_GPIO_PIN_LEFT (1<<3)
#define KEYS_GPIO_REG_UP pinl
#define KEYS_GPIO_PIN_UP (1<<1)
#define KEYS_GPIO_REG_DOWN pinl
#define KEYS_GPIO_PIN_DOWN (1<<0)
// Trims
#define TRIMS_GPIO_REG_LHL pinj
#define TRIMS_GPIO_REG_LVD pinj
#define TRIMS_GPIO_REG_RVU pinj
#define TRIMS_GPIO_REG_RHL pinj
#define TRIMS_GPIO_REG_LHR pinj
#define TRIMS_GPIO_REG_LVU pinj
#define TRIMS_GPIO_REG_RVD pinj
#define TRIMS_GPIO_REG_RHR pinj
#define TRIMS_GPIO_PIN_LHL (1<<0)
#define TRIMS_GPIO_PIN_LVD (1<<2)
#define TRIMS_GPIO_PIN_RVU (1<<5)
#define TRIMS_GPIO_PIN_RHL (1<<6)
#define TRIMS_GPIO_PIN_LHR (1<<1)
#define TRIMS_GPIO_PIN_LVU (1<<3)
#define TRIMS_GPIO_PIN_RVD (1<<4)
#define TRIMS_GPIO_PIN_RHR (1<<7)
#define TIMER_16KHZ_VECT TIMER2_OVF_vect
#define COUNTER_16KHZ TCNT2
#define TIMER_10MS_VECT TIMER2_COMPA_vect
#define TIMER_10MS_COMPVAL OCR2A
#define PAUSE_10MS_INTERRUPT() TIMSK2 &= ~(1<<OCIE2A)
#define RESUME_10MS_INTERRUPT() TIMSK2 |= (1<<OCIE2A)
#define PAUSE_PPMIN_INTERRUPT() TIMSK3 &= ~(1<<ICIE3)
#define RESUME_PPMIN_INTERRUPT() TIMSK3 |= (1<<ICIE3)
#define SLAVE_MODE() (PING & (1<<INP_G_RF_POW))
#define JACK_PPM_OUT() PORTG |= (1<<OUT_G_SIM_CTL)
#define JACK_PPM_IN() PORTG &= ~(1<<OUT_G_SIM_CTL)
// SD driver
#define BLOCK_SIZE 512 /* Block Size in Bytes */
#define sdDone()
#define SD_IS_HC() (0)
#define SD_GET_SPEED() (0)
#if !defined(SIMU)
bool sdMounted();
void sdMountPoll();
void sdPoll10ms();
#endif
#define speakerOn() TCCR0A |= (1 << COM0A0)
#define speakerOff() TCCR0A &= ~(1 << COM0A0)
// Backlight driver
#define OUT_C_LIGHT 0
#define backlightEnable() PORTC |= (1<<OUT_C_LIGHT)
#define backlightDisable() PORTC &= ~(1<<OUT_C_LIGHT)
#define isBacklightEnabled() (PORTC & (1<<OUT_C_LIGHT))
#define BACKLIGHT_ENABLE() backlightEnable()
#define BACKLIGHT_DISABLE() backlightDisable()
#define INP_E_PPM_IN 7
#define INP_E_ROT_ENC_1_B 6
#define INP_E_ROT_ENC_1_A 5
#define INP_E_USB_D_PLS 4
#define OUT_E_BUZZER 3
#define INP_E_USB_D_NEG 2
#define INP_E_TELEM_RX 1
#define OUT_E_TELEM_TX 0
#define OUT_D_HAPTIC 7
#define INP_D_SPARE4 6
#define INP_D_ROT_ENC_2_PUSH 5
#define INP_D_ROT_ENC_1_PUSH 4
#define OUT_D_ROT_ENC_2_B 3
#define INP_D_ROT_ENC_2_A 2
#define INP_D_I2C_SCL 1
#define INP_D_I2C_SDA 0
#define INP_G_Gear 5
#define INP_G_ThrCt 2
#define OUT_G_SIM_CTL 4 //1 : phone-jack=ppm_in
#define INP_G_ID1 3
#define INP_G_RF_POW 1
#define INP_G_RuddDR 0
#define INP_C_AileDR 7
#define INP_C_ElevDR 6
#define OUT_B_Speaker 7
#define OUT_B_PPM 6 // will be switched by TCNT1==OCR1B in hardware
#define INP_B_Trainer 5
#define INP_B_ID2 4
#if defined(VOICE)
#define OUT_H_14DRESET 3
#define OUT_H_14DCLK 4
#define OUT_H_14DDATA 5
#define INP_H_14DBUSY 6
#endif
// Keys driver
#define TRIMS_PRESSED() (~PINJ)
#define KEYS_PRESSED() (~PINL) // used only for DBLKEYS code.
// LCD driver
#define PORTA_LCD_DAT PORTA
#define PORTC_LCD_CTRL PORTC
#define OUT_C_LCD_E 5
#define OUT_C_LCD_RnW 4
#define OUT_C_LCD_A0 3
#define OUT_C_LCD_RES 2
#define OUT_C_LCD_CS1 1
// Power driver
uint8_t pwrCheck();
void pwrOff();
#define UNEXPECTED_SHUTDOWN() ((mcusr & (1 << WDRF)) || g_eeGeneral.unexpectedShutdown)
// USB fake driver
#define usbPlugged() false
// Haptic driver
#define hapticOn() PORTD &= ~(1 << OUT_D_HAPTIC)
#define hapticOff() PORTD |= (1 << OUT_D_HAPTIC)
// Rotary encoder driver
#define REA_DOWN() (~PIND & 0x20)
#define REB_DOWN() (~PIND & 0x10)
#define ROTENC_DOWN() (REA_DOWN() || REB_DOWN())
// Buzzer driver
#define buzzerOn() PORTE |= (1 << OUT_E_BUZZER)
#define buzzerOff() PORTE &= ~(1 << OUT_E_BUZZER)
#endif // _BOARD_GRUVIN9X_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BOARD_GRUVIN9X_H_
#define _BOARD_GRUVIN9X_H_
#include "../common/avr/board_avr.h"
// Board driver
void boardInit(void);
#define boardOff() pwrOff()
// Keys
#define KEYS_GPIO_REG_MENU pinl
#define KEYS_GPIO_PIN_MENU (1<<4)
#define KEYS_GPIO_REG_EXIT pinl
#define KEYS_GPIO_PIN_EXIT (1<<5)
#define KEYS_GPIO_REG_RIGHT pinl
#define KEYS_GPIO_PIN_RIGHT (1<<2)
#define KEYS_GPIO_REG_LEFT pinl
#define KEYS_GPIO_PIN_LEFT (1<<3)
#define KEYS_GPIO_REG_UP pinl
#define KEYS_GPIO_PIN_UP (1<<1)
#define KEYS_GPIO_REG_DOWN pinl
#define KEYS_GPIO_PIN_DOWN (1<<0)
// Trims
#define TRIMS_GPIO_REG_LHL pinj
#define TRIMS_GPIO_REG_LVD pinj
#define TRIMS_GPIO_REG_RVU pinj
#define TRIMS_GPIO_REG_RHL pinj
#define TRIMS_GPIO_REG_LHR pinj
#define TRIMS_GPIO_REG_LVU pinj
#define TRIMS_GPIO_REG_RVD pinj
#define TRIMS_GPIO_REG_RHR pinj
#define TRIMS_GPIO_PIN_LHL (1<<0)
#define TRIMS_GPIO_PIN_LVD (1<<2)
#define TRIMS_GPIO_PIN_RVU (1<<5)
#define TRIMS_GPIO_PIN_RHL (1<<6)
#define TRIMS_GPIO_PIN_LHR (1<<1)
#define TRIMS_GPIO_PIN_LVU (1<<3)
#define TRIMS_GPIO_PIN_RVD (1<<4)
#define TRIMS_GPIO_PIN_RHR (1<<7)
#define TIMER_16KHZ_VECT TIMER2_OVF_vect
#define COUNTER_16KHZ TCNT2
#define TIMER_10MS_VECT TIMER2_COMPA_vect
#define TIMER_10MS_COMPVAL OCR2A
#define PAUSE_10MS_INTERRUPT() TIMSK2 &= ~(1<<OCIE2A)
#define RESUME_10MS_INTERRUPT() TIMSK2 |= (1<<OCIE2A)
#define PAUSE_PPMIN_INTERRUPT() TIMSK3 &= ~(1<<ICIE3)
#define RESUME_PPMIN_INTERRUPT() TIMSK3 |= (1<<ICIE3)
#define SLAVE_MODE() (PING & (1<<INP_G_RF_POW))
#define JACK_PPM_OUT() PORTG |= (1<<OUT_G_SIM_CTL)
#define JACK_PPM_IN() PORTG &= ~(1<<OUT_G_SIM_CTL)
// SD driver
#define BLOCK_SIZE 512 /* Block Size in Bytes */
#define sdDone()
#define SD_IS_HC() (0)
#define SD_GET_SPEED() (0)
#if !defined(SIMU)
bool sdMounted();
void sdMountPoll();
void sdPoll10ms();
#endif
#define speakerOn() TCCR0A |= (1 << COM0A0)
#define speakerOff() TCCR0A &= ~(1 << COM0A0)
// Backlight driver
#define OUT_C_LIGHT 0
#define backlightEnable() PORTC |= (1<<OUT_C_LIGHT)
#define backlightDisable() PORTC &= ~(1<<OUT_C_LIGHT)
#define isBacklightEnabled() (PORTC & (1<<OUT_C_LIGHT))
#define BACKLIGHT_ENABLE() backlightEnable()
#define BACKLIGHT_DISABLE() backlightDisable()
#define INP_E_PPM_IN 7
#define INP_E_ROT_ENC_1_B 6
#define INP_E_ROT_ENC_1_A 5
#define INP_E_USB_D_PLS 4
#define OUT_E_BUZZER 3
#define INP_E_USB_D_NEG 2
#define INP_E_TELEM_RX 1
#define OUT_E_TELEM_TX 0
#define OUT_D_HAPTIC 7
#define INP_D_SPARE4 6
#define INP_D_ROT_ENC_2_PUSH 5
#define INP_D_ROT_ENC_1_PUSH 4
#define OUT_D_ROT_ENC_2_B 3
#define INP_D_ROT_ENC_2_A 2
#define INP_D_I2C_SCL 1
#define INP_D_I2C_SDA 0
#define INP_G_Gear 5
#define INP_G_ThrCt 2
#define OUT_G_SIM_CTL 4 //1 : phone-jack=ppm_in
#define INP_G_ID1 3
#define INP_G_RF_POW 1
#define INP_G_RuddDR 0
#define INP_C_AileDR 7
#define INP_C_ElevDR 6
#define OUT_B_Speaker 7
#define OUT_B_PPM 6 // will be switched by TCNT1==OCR1B in hardware
#define INP_B_Trainer 5
#define INP_B_ID2 4
#if defined(VOICE)
#define OUT_H_14DRESET 3
#define OUT_H_14DCLK 4
#define OUT_H_14DDATA 5
#define INP_H_14DBUSY 6
#endif
// Keys driver
#define TRIMS_PRESSED() (~PINJ)
#define KEYS_PRESSED() (~PINL) // used only for DBLKEYS code.
// LCD driver
#define PORTA_LCD_DAT PORTA
#define PORTC_LCD_CTRL PORTC
#define OUT_C_LCD_E 5
#define OUT_C_LCD_RnW 4
#define OUT_C_LCD_A0 3
#define OUT_C_LCD_RES 2
#define OUT_C_LCD_CS1 1
// Power driver
uint8_t pwrCheck();
void pwrOff();
#define UNEXPECTED_SHUTDOWN() ((mcusr & (1 << WDRF)) || g_eeGeneral.unexpectedShutdown)
// USB fake driver
#define usbPlugged() false
// Haptic driver
#define hapticOn() PORTD &= ~(1 << OUT_D_HAPTIC)
#define hapticOff() PORTD |= (1 << OUT_D_HAPTIC)
// Rotary encoder driver
#define REA_DOWN() (~PIND & 0x20)
#define REB_DOWN() (~PIND & 0x10)
#define ROTENC_DOWN() (REA_DOWN() || REB_DOWN())
// Buzzer driver
#define buzzerOn() PORTE |= (1 << OUT_E_BUZZER)
#define buzzerOff() PORTE &= ~(1 << OUT_E_BUZZER)
#endif // _BOARD_GRUVIN9X_H_

File diff suppressed because it is too large Load diff

View file

@ -1,304 +1,304 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*--------------------------------------------------------------------------*/
/* RTC controls */
#include "opentx.h"
#include "FatFs/integer.h"
typedef struct {
WORD year; /* 2000..2099 */
BYTE month; /* 1..12 */
BYTE mday; /* 1.. 31 */
BYTE wday; /* 1..7 */
BYTE hour; /* 0..23 */
BYTE min; /* 0..59 */
BYTE sec; /* 0..59 */
} RTC;
#define SCL_LOW() DDRD |= 0x01 /* SCL = LOW */
#define SCL_HIGH() DDRD &= ~0x01 /* SCL = High-Z */
#define SCL_VAL ((PIND & 0x01) ? 1 : 0) /* SCL input level */
#define SDA_LOW() DDRD |= 0x02 /* SDA = LOW */
#define SDA_HIGH() DDRD &= ~0x02 /* SDA = High-Z */
#define SDA_VAL ((PIND & 0x02) ? 1 : 0) /* SDA input level */
/*-------------------------------------------------*/
/* I2C bus protocol */
static
void iic_delay (void)
{
#ifndef SIMU
for (int n = 4; n; n--) PINB;
#endif
}
/* Generate start condition on the IIC bus */
static
void iic_start (void)
{
SDA_HIGH();
iic_delay();
SCL_HIGH();
iic_delay();
SDA_LOW();
iic_delay();
SCL_LOW();
iic_delay();
}
/* Generate stop condition on the IIC bus */
static
void iic_stop (void)
{
SDA_LOW();
iic_delay();
SCL_HIGH();
iic_delay();
SDA_HIGH();
iic_delay();
}
/* Send a byte to the IIC bus */
static
int iic_send (BYTE dat)
{
BYTE b = 0x80;
int ack;
do {
if (dat & b) { /* SDA = Z/L */
SDA_HIGH();
} else {
SDA_LOW();
}
iic_delay();
SCL_HIGH();
iic_delay();
SCL_LOW();
iic_delay();
} while (b >>= 1);
SDA_HIGH();
iic_delay();
SCL_HIGH();
ack = SDA_VAL ? 0 : 1; /* Sample ACK */
iic_delay();
SCL_LOW();
iic_delay();
return ack;
}
/* Receive a byte from the IIC bus */
static
BYTE iic_rcvr (int ack)
{
UINT d = 1;
do {
d <<= 1;
SCL_HIGH();
if (SDA_VAL) d++;
iic_delay();
SCL_LOW();
iic_delay();
} while (d < 0x100);
if (ack) { /* SDA = ACK */
SDA_LOW();
} else {
SDA_HIGH();
}
iic_delay();
SCL_HIGH();
iic_delay();
SCL_LOW();
SDA_HIGH();
iic_delay();
return (BYTE)d;
}
/*-------------------------------------------------*/
/* I2C block read/write controls */
int iic_read (
BYTE dev, /* Device address */
UINT adr, /* Read start address */
UINT cnt, /* Read byte count */
BYTE *buff /* Read data buffer */
)
{
BYTE *rbuff = buff;
int n;
if (!cnt) return 0;
n = 10;
do { /* Select device */
iic_start();
} while (!iic_send(dev) && --n);
if (n) {
if (iic_send((BYTE)adr)) { /* Set start address */
iic_start(); /* Reselect device in read mode */
if (iic_send(dev | 1)) {
do { /* Receive data */
cnt--;
*rbuff++ = iic_rcvr(cnt ? 1 : 0);
} while (cnt);
}
}
}
iic_stop(); /* Deselect device */
return cnt ? 0 : 1;
}
int iic_write (
BYTE dev, /* Device address */
UINT adr, /* Write start address */
UINT cnt, /* Write byte count */
const BYTE *buff /* Data to be written */
)
{
const BYTE *wbuff = buff;
int n;
if (!cnt) return 0;
n = 10;
do { /* Select device */
iic_start();
} while (!iic_send(dev) && --n);
if (n) {
if (iic_send((BYTE)adr)) { /* Set start address */
do { /* Send data */
if (!iic_send(*wbuff++)) break;
} while (--cnt);
}
}
iic_stop(); /* Deselect device */
return cnt ? 0 : 1;
}
/*-------------------------------------------------*/
/* RTC functions */
int g9x_rtcGetTime (RTC *rtc)
{
BYTE buf[8];
if (!iic_read(0xD0, 0, 7, buf)) return 0;
rtc->sec = (buf[0] & 0x0F) + ((buf[0] >> 4) & 7) * 10;
rtc->min = (buf[1] & 0x0F) + (buf[1] >> 4) * 10;
rtc->hour = (buf[2] & 0x0F) + ((buf[2] >> 4) & 3) * 10;
rtc->wday = (buf[2] & 0x07);
rtc->mday = (buf[4] & 0x0F) + ((buf[4] >> 4) & 3) * 10;
rtc->month = (buf[5] & 0x0F) + ((buf[5] >> 4) & 1) * 10;
rtc->year = 2000 + (buf[6] & 0x0F) + (buf[6] >> 4) * 10;
return 1;
}
int g9x_rtcSetTime (const RTC *rtc)
{
BYTE buf[8];
buf[0] = rtc->sec / 10 * 16 + rtc->sec % 10;
buf[1] = rtc->min / 10 * 16 + rtc->min % 10;
buf[2] = rtc->hour / 10 * 16 + rtc->hour % 10;
buf[3] = rtc->wday & 7;
buf[4] = rtc->mday / 10 * 16 + rtc->mday % 10;
buf[5] = rtc->month / 10 * 16 + rtc->month % 10;
buf[6] = (rtc->year - 2000) / 10 * 16 + (rtc->year - 2000) % 10;
return iic_write(0xD0, 0, 7, buf);
}
void rtcGetTime(struct gtm * utm)
{
RTC rtc = {0,0,0,0,0,0,0};
g9x_rtcGetTime(&rtc);
utm->tm_year = rtc.year - TM_YEAR_BASE;
utm->tm_mon = rtc.month - 1;
utm->tm_mday = rtc.mday;
utm->tm_hour = rtc.hour;
utm->tm_min = rtc.min;
utm->tm_sec = rtc.sec;
utm->tm_wday = rtc.wday - 1;
}
void rtcSetTime(const struct gtm * t)
{
g_ms100 = 0; // start of next second begins now
RTC rtc;
rtc.year = t->tm_year + TM_YEAR_BASE;
rtc.month = t->tm_mon + 1;
rtc.mday = t->tm_mday;
rtc.hour = t->tm_hour;
rtc.min = t->tm_min;
rtc.sec = t->tm_sec;
rtc.wday = t->tm_wday + 1;
g9x_rtcSetTime(&rtc);
}
void rtcInit (void)
{
BYTE buf[8]; /* RTC R/W buffer */
UINT adr;
/* Read RTC registers */
if (!iic_read(0xD0, 0, 8, buf)) return; /* IIC error */
if (buf[7] & 0x20) { /* When data has been volatiled, set default time */
/* Clear nv-ram. Reg[8..63] */
memset(buf, 0, 8);
for (adr = 8; adr < 64; adr += 8)
iic_write(0x0D, adr, 8, buf);
/* Reset time to Jan 1, '08. Reg[0..7] */
buf[4] = 1; buf[5] = 1; buf[6] = 8;
iic_write(0x0D, 0, 8, buf);
}
struct gtm utm;
rtcGetTime(&utm);
g_rtcTime = gmktime(&utm);
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*--------------------------------------------------------------------------*/
/* RTC controls */
#include "opentx.h"
#include "FatFs/integer.h"
typedef struct {
WORD year; /* 2000..2099 */
BYTE month; /* 1..12 */
BYTE mday; /* 1.. 31 */
BYTE wday; /* 1..7 */
BYTE hour; /* 0..23 */
BYTE min; /* 0..59 */
BYTE sec; /* 0..59 */
} RTC;
#define SCL_LOW() DDRD |= 0x01 /* SCL = LOW */
#define SCL_HIGH() DDRD &= ~0x01 /* SCL = High-Z */
#define SCL_VAL ((PIND & 0x01) ? 1 : 0) /* SCL input level */
#define SDA_LOW() DDRD |= 0x02 /* SDA = LOW */
#define SDA_HIGH() DDRD &= ~0x02 /* SDA = High-Z */
#define SDA_VAL ((PIND & 0x02) ? 1 : 0) /* SDA input level */
/*-------------------------------------------------*/
/* I2C bus protocol */
static
void iic_delay (void)
{
#ifndef SIMU
for (int n = 4; n; n--) PINB;
#endif
}
/* Generate start condition on the IIC bus */
static
void iic_start (void)
{
SDA_HIGH();
iic_delay();
SCL_HIGH();
iic_delay();
SDA_LOW();
iic_delay();
SCL_LOW();
iic_delay();
}
/* Generate stop condition on the IIC bus */
static
void iic_stop (void)
{
SDA_LOW();
iic_delay();
SCL_HIGH();
iic_delay();
SDA_HIGH();
iic_delay();
}
/* Send a byte to the IIC bus */
static
int iic_send (BYTE dat)
{
BYTE b = 0x80;
int ack;
do {
if (dat & b) { /* SDA = Z/L */
SDA_HIGH();
} else {
SDA_LOW();
}
iic_delay();
SCL_HIGH();
iic_delay();
SCL_LOW();
iic_delay();
} while (b >>= 1);
SDA_HIGH();
iic_delay();
SCL_HIGH();
ack = SDA_VAL ? 0 : 1; /* Sample ACK */
iic_delay();
SCL_LOW();
iic_delay();
return ack;
}
/* Receive a byte from the IIC bus */
static
BYTE iic_rcvr (int ack)
{
UINT d = 1;
do {
d <<= 1;
SCL_HIGH();
if (SDA_VAL) d++;
iic_delay();
SCL_LOW();
iic_delay();
} while (d < 0x100);
if (ack) { /* SDA = ACK */
SDA_LOW();
} else {
SDA_HIGH();
}
iic_delay();
SCL_HIGH();
iic_delay();
SCL_LOW();
SDA_HIGH();
iic_delay();
return (BYTE)d;
}
/*-------------------------------------------------*/
/* I2C block read/write controls */
int iic_read (
BYTE dev, /* Device address */
UINT adr, /* Read start address */
UINT cnt, /* Read byte count */
BYTE *buff /* Read data buffer */
)
{
BYTE *rbuff = buff;
int n;
if (!cnt) return 0;
n = 10;
do { /* Select device */
iic_start();
} while (!iic_send(dev) && --n);
if (n) {
if (iic_send((BYTE)adr)) { /* Set start address */
iic_start(); /* Reselect device in read mode */
if (iic_send(dev | 1)) {
do { /* Receive data */
cnt--;
*rbuff++ = iic_rcvr(cnt ? 1 : 0);
} while (cnt);
}
}
}
iic_stop(); /* Deselect device */
return cnt ? 0 : 1;
}
int iic_write (
BYTE dev, /* Device address */
UINT adr, /* Write start address */
UINT cnt, /* Write byte count */
const BYTE *buff /* Data to be written */
)
{
const BYTE *wbuff = buff;
int n;
if (!cnt) return 0;
n = 10;
do { /* Select device */
iic_start();
} while (!iic_send(dev) && --n);
if (n) {
if (iic_send((BYTE)adr)) { /* Set start address */
do { /* Send data */
if (!iic_send(*wbuff++)) break;
} while (--cnt);
}
}
iic_stop(); /* Deselect device */
return cnt ? 0 : 1;
}
/*-------------------------------------------------*/
/* RTC functions */
int g9x_rtcGetTime (RTC *rtc)
{
BYTE buf[8];
if (!iic_read(0xD0, 0, 7, buf)) return 0;
rtc->sec = (buf[0] & 0x0F) + ((buf[0] >> 4) & 7) * 10;
rtc->min = (buf[1] & 0x0F) + (buf[1] >> 4) * 10;
rtc->hour = (buf[2] & 0x0F) + ((buf[2] >> 4) & 3) * 10;
rtc->wday = (buf[2] & 0x07);
rtc->mday = (buf[4] & 0x0F) + ((buf[4] >> 4) & 3) * 10;
rtc->month = (buf[5] & 0x0F) + ((buf[5] >> 4) & 1) * 10;
rtc->year = 2000 + (buf[6] & 0x0F) + (buf[6] >> 4) * 10;
return 1;
}
int g9x_rtcSetTime (const RTC *rtc)
{
BYTE buf[8];
buf[0] = rtc->sec / 10 * 16 + rtc->sec % 10;
buf[1] = rtc->min / 10 * 16 + rtc->min % 10;
buf[2] = rtc->hour / 10 * 16 + rtc->hour % 10;
buf[3] = rtc->wday & 7;
buf[4] = rtc->mday / 10 * 16 + rtc->mday % 10;
buf[5] = rtc->month / 10 * 16 + rtc->month % 10;
buf[6] = (rtc->year - 2000) / 10 * 16 + (rtc->year - 2000) % 10;
return iic_write(0xD0, 0, 7, buf);
}
void rtcGetTime(struct gtm * utm)
{
RTC rtc = {0,0,0,0,0,0,0};
g9x_rtcGetTime(&rtc);
utm->tm_year = rtc.year - TM_YEAR_BASE;
utm->tm_mon = rtc.month - 1;
utm->tm_mday = rtc.mday;
utm->tm_hour = rtc.hour;
utm->tm_min = rtc.min;
utm->tm_sec = rtc.sec;
utm->tm_wday = rtc.wday - 1;
}
void rtcSetTime(const struct gtm * t)
{
g_ms100 = 0; // start of next second begins now
RTC rtc;
rtc.year = t->tm_year + TM_YEAR_BASE;
rtc.month = t->tm_mon + 1;
rtc.mday = t->tm_mday;
rtc.hour = t->tm_hour;
rtc.min = t->tm_min;
rtc.sec = t->tm_sec;
rtc.wday = t->tm_wday + 1;
g9x_rtcSetTime(&rtc);
}
void rtcInit (void)
{
BYTE buf[8]; /* RTC R/W buffer */
UINT adr;
/* Read RTC registers */
if (!iic_read(0xD0, 0, 8, buf)) return; /* IIC error */
if (buf[7] & 0x20) { /* When data has been volatiled, set default time */
/* Clear nv-ram. Reg[8..63] */
memset(buf, 0, 8);
for (adr = 8; adr < 64; adr += 8)
iic_write(0x0D, adr, 8, buf);
/* Reset time to Jan 1, '08. Reg[0..7] */
buf[4] = 1; buf[5] = 1; buf[6] = 8;
iic_write(0x0D, 0, 8, buf);
}
struct gtm utm;
rtcGetTime(&utm);
g_rtcTime = gmktime(&utm);
}

View file

@ -1,260 +1,260 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint16_t adcValues[NUM_ANALOGS] __DMA;
#define ADC_CS_HIGH() (ADC_SPI_GPIO->BSRRL = ADC_SPI_PIN_CS)
#define ADC_CS_LOW() (ADC_SPI_GPIO->BSRRH = ADC_SPI_PIN_CS)
#define SPI_STICK1 0
#define SPI_STICK2 1
#define SPI_STICK3 2
#define SPI_STICK4 3
#define SPI_S1 4
#define SPI_6POS 5
#define SPI_S2 6
#define SPI_LS 7
#define SPI_RS 8
#define SPI_TX_VOLTAGE 9
#define SPI_L2 10
#define SPI_L1 11
#define RESETCMD 0x4000
#define MANUAL_MODE 0x1000 // manual mode channel 0
#define SAMPTIME 2 // sample time = 28 cycles
uint16_t SPIx_ReadWriteByte(uint16_t value)
{
while (SPI_I2S_GetFlagStatus(ADC_SPI, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(ADC_SPI, value);
while (SPI_I2S_GetFlagStatus(ADC_SPI, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(ADC_SPI);
}
static void ADS7952_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitStructure.GPIO_Pin = ADC_SPI_PIN_MISO | ADC_SPI_PIN_SCK | ADC_SPI_PIN_MOSI;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(ADC_SPI_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = ADC_SPI_PIN_CS;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(ADC_SPI_GPIO, &GPIO_InitStructure);
GPIO_PinAFConfig(ADC_SPI_GPIO, ADC_SPI_PinSource_SCK, ADC_GPIO_AF);
GPIO_PinAFConfig(ADC_SPI_GPIO, ADC_SPI_PinSource_MISO, ADC_GPIO_AF);
GPIO_PinAFConfig(ADC_SPI_GPIO, ADC_SPI_PinSource_MOSI, ADC_GPIO_AF);
SPI_I2S_DeInit(ADC_SPI);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(ADC_SPI, &SPI_InitStructure);
SPI_Cmd(ADC_SPI, ENABLE);
SPI_I2S_ITConfig(ADC_SPI, SPI_I2S_IT_TXE, DISABLE);
SPI_I2S_ITConfig(ADC_SPI, SPI_I2S_IT_RXNE, DISABLE);
ADC_CS_HIGH();
delay_01us(1);
ADC_CS_LOW();
SPIx_ReadWriteByte(RESETCMD);
ADC_CS_HIGH();
delay_01us(1);
ADC_CS_LOW();
SPIx_ReadWriteByte(MANUAL_MODE);
ADC_CS_HIGH();
}
void adcInit()
{
ADS7952_Init();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN_MOUSE1 | ADC_GPIO_PIN_MOUSE2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(ADC_GPIO_MOUSE, &GPIO_InitStructure);
ADC3->CR1 = ADC_CR1_SCAN;
ADC3->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
ADC3->SQR1 = (2-1) << 20;
ADC3->SQR2 = 0;
ADC3->SQR3 = ADC_IN_MOUSE1 + (ADC_IN_MOUSE2<<5);
ADC3->SMPR1 = 0;
ADC3->SMPR2 = (ADC_SAMPTIME<<(3*ADC_IN_MOUSE1)) + (ADC_SAMPTIME<<(3*ADC_IN_MOUSE2));
ADC->CCR = 0;
// Enable the DMA channel here, DMA2 stream 1, channel 2
ADC_DMA_Stream->CR = DMA_SxCR_PL | DMA_SxCR_CHSEL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC;
ADC_DMA_Stream->PAR = CONVERT_PTR_UINT(&ADC3->DR);
ADC_DMA_Stream->M0AR = CONVERT_PTR_UINT(&adcValues[MOUSE1]);
ADC_DMA_Stream->NDTR = 2;
ADC_DMA_Stream->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0;
}
const uint16_t adcCommands[MOUSE1+2] =
{
MANUAL_MODE | (SPI_STICK1 << 7),
MANUAL_MODE | (SPI_STICK2 << 7),
MANUAL_MODE | (SPI_STICK3 << 7),
MANUAL_MODE | (SPI_STICK4 << 7),
MANUAL_MODE | (SPI_S1 << 7),
MANUAL_MODE | (SPI_6POS << 7),
MANUAL_MODE | (SPI_S2 << 7),
MANUAL_MODE | (SPI_L1 << 7),
MANUAL_MODE | (SPI_L2 << 7),
MANUAL_MODE | (SPI_LS << 7),
MANUAL_MODE | (SPI_RS << 7),
MANUAL_MODE | (SPI_TX_VOLTAGE << 7),
MANUAL_MODE | (0 << 7), // small joystick left/right
MANUAL_MODE | (0 << 7) // small joystick up/down
};
void adcReadSPIDummy()
{
// A dummy command to get things started
// (because the sampled data is lagging behind for two command cycles)
ADC_CS_LOW();
delay_01us(1);
SPIx_ReadWriteByte(adcCommands[0]);
ADC_CS_HIGH();
delay_01us(1);
}
uint32_t adcReadNextSPIChannel(uint8_t index)
{
uint32_t result = 0;
// This delay is to allow charging of ADC input capacitor
// after the MUX changes from one channel to the other.
// It was determined experimentally. Biggest problem seems to be
// the cross-talk between A4:S1 and A5:MULTIPOS. Changing S1 for one extreme
// to the other resulted in A5 change of:
//
// delay value A5 change Time needed for adcRead()
// 1 16 0.154ms - 0.156ms
// 38 5 0.197ms - 0.199ms
// 62 0 0.225ms - 0.243ms
delay_01us(40);
for (uint8_t i = 0; i < 4; i++) {
ADC_CS_LOW();
delay_01us(1);
// command is changed to the next index for the last two readings
// (because the sampled data is lagging behind for two command cycles)
uint16_t val = (0x0fff & SPIx_ReadWriteByte(adcCommands[(i>1) ? index+1 : index]));
#if defined(JITTER_MEASURE)
if (JITTER_MEASURE_ACTIVE()) {
rawJitter[index].measure(val);
}
#endif
ADC_CS_HIGH();
delay_01us(1);
result += val;
}
return result >> 2;
}
void adcOnChipReadStart()
{
ADC_DMA_Stream->CR &= ~DMA_SxCR_EN; // Disable DMA
ADC3->SR &= ~(uint32_t)(ADC_SR_EOC | ADC_SR_STRT | ADC_SR_OVR);
ADC_DMA->LIFCR = DMA_LIFCR_CTCIF0 | DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0 | DMA_LIFCR_CFEIF0; // Write ones to clear bits
ADC_DMA_Stream->M0AR = CONVERT_PTR_UINT(&adcValues[MOUSE1]);
ADC_DMA_Stream->NDTR = 2;
ADC_DMA_Stream->CR |= DMA_SxCR_EN; // Enable DMA
ADC3->CR2 |= (uint32_t)ADC_CR2_SWSTART;
}
bool adcOnChipReadFinished()
{
return (ADC_DMA->LISR & DMA_LISR_TCIF0);
}
void adcRead()
{
uint16_t temp[NUM_ANALOGS-MOUSE1] = { 0 };
uint8_t noInternalReads = 0;
adcOnChipReadStart();
adcReadSPIDummy();
adcReadSPIDummy();
for (uint32_t index=0; index<MOUSE1; index++) {
adcValues[index] = adcReadNextSPIChannel(index);
if (noInternalReads < 4 && adcOnChipReadFinished()) {
for (uint8_t x=0; x<NUM_ANALOGS-MOUSE1; x++) {
uint16_t val = adcValues[MOUSE1+x];
#if defined(JITTER_MEASURE)
if (JITTER_MEASURE_ACTIVE()) {
rawJitter[MOUSE1+x].measure(val);
}
#endif
temp[x] += val;
}
if (++noInternalReads < 4) {
adcOnChipReadStart();
}
}
}
#if defined(DEBUG)
if (noInternalReads != 4) {
TRACE("Internal ADC problem: reads: %d", noInternalReads);
}
#endif
for (uint8_t x=0; x<NUM_ANALOGS-MOUSE1; x++) {
adcValues[MOUSE1+x] = temp[x] >> 2;
}
}
#if !defined(SIMU)
const int8_t ana_direction[NUM_ANALOGS] = {1,-1,1,-1, -1,1,-1, -1,-1, -1,1, 0,0,0};
uint16_t getAnalogValue(uint8_t index)
{
if (ana_direction[index] < 0)
return 4095 - adcValues[index];
else
return adcValues[index];
}
#endif // #if !defined(SIMU)
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint16_t adcValues[NUM_ANALOGS] __DMA;
#define ADC_CS_HIGH() (ADC_SPI_GPIO->BSRRL = ADC_SPI_PIN_CS)
#define ADC_CS_LOW() (ADC_SPI_GPIO->BSRRH = ADC_SPI_PIN_CS)
#define SPI_STICK1 0
#define SPI_STICK2 1
#define SPI_STICK3 2
#define SPI_STICK4 3
#define SPI_S1 4
#define SPI_6POS 5
#define SPI_S2 6
#define SPI_LS 7
#define SPI_RS 8
#define SPI_TX_VOLTAGE 9
#define SPI_L2 10
#define SPI_L1 11
#define RESETCMD 0x4000
#define MANUAL_MODE 0x1000 // manual mode channel 0
#define SAMPTIME 2 // sample time = 28 cycles
uint16_t SPIx_ReadWriteByte(uint16_t value)
{
while (SPI_I2S_GetFlagStatus(ADC_SPI, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(ADC_SPI, value);
while (SPI_I2S_GetFlagStatus(ADC_SPI, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(ADC_SPI);
}
static void ADS7952_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitStructure.GPIO_Pin = ADC_SPI_PIN_MISO | ADC_SPI_PIN_SCK | ADC_SPI_PIN_MOSI;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(ADC_SPI_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = ADC_SPI_PIN_CS;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(ADC_SPI_GPIO, &GPIO_InitStructure);
GPIO_PinAFConfig(ADC_SPI_GPIO, ADC_SPI_PinSource_SCK, ADC_GPIO_AF);
GPIO_PinAFConfig(ADC_SPI_GPIO, ADC_SPI_PinSource_MISO, ADC_GPIO_AF);
GPIO_PinAFConfig(ADC_SPI_GPIO, ADC_SPI_PinSource_MOSI, ADC_GPIO_AF);
SPI_I2S_DeInit(ADC_SPI);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(ADC_SPI, &SPI_InitStructure);
SPI_Cmd(ADC_SPI, ENABLE);
SPI_I2S_ITConfig(ADC_SPI, SPI_I2S_IT_TXE, DISABLE);
SPI_I2S_ITConfig(ADC_SPI, SPI_I2S_IT_RXNE, DISABLE);
ADC_CS_HIGH();
delay_01us(1);
ADC_CS_LOW();
SPIx_ReadWriteByte(RESETCMD);
ADC_CS_HIGH();
delay_01us(1);
ADC_CS_LOW();
SPIx_ReadWriteByte(MANUAL_MODE);
ADC_CS_HIGH();
}
void adcInit()
{
ADS7952_Init();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN_MOUSE1 | ADC_GPIO_PIN_MOUSE2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(ADC_GPIO_MOUSE, &GPIO_InitStructure);
ADC3->CR1 = ADC_CR1_SCAN;
ADC3->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
ADC3->SQR1 = (2-1) << 20;
ADC3->SQR2 = 0;
ADC3->SQR3 = ADC_IN_MOUSE1 + (ADC_IN_MOUSE2<<5);
ADC3->SMPR1 = 0;
ADC3->SMPR2 = (ADC_SAMPTIME<<(3*ADC_IN_MOUSE1)) + (ADC_SAMPTIME<<(3*ADC_IN_MOUSE2));
ADC->CCR = 0;
// Enable the DMA channel here, DMA2 stream 1, channel 2
ADC_DMA_Stream->CR = DMA_SxCR_PL | DMA_SxCR_CHSEL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC;
ADC_DMA_Stream->PAR = CONVERT_PTR_UINT(&ADC3->DR);
ADC_DMA_Stream->M0AR = CONVERT_PTR_UINT(&adcValues[MOUSE1]);
ADC_DMA_Stream->NDTR = 2;
ADC_DMA_Stream->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0;
}
const uint16_t adcCommands[MOUSE1+2] =
{
MANUAL_MODE | (SPI_STICK1 << 7),
MANUAL_MODE | (SPI_STICK2 << 7),
MANUAL_MODE | (SPI_STICK3 << 7),
MANUAL_MODE | (SPI_STICK4 << 7),
MANUAL_MODE | (SPI_S1 << 7),
MANUAL_MODE | (SPI_6POS << 7),
MANUAL_MODE | (SPI_S2 << 7),
MANUAL_MODE | (SPI_L1 << 7),
MANUAL_MODE | (SPI_L2 << 7),
MANUAL_MODE | (SPI_LS << 7),
MANUAL_MODE | (SPI_RS << 7),
MANUAL_MODE | (SPI_TX_VOLTAGE << 7),
MANUAL_MODE | (0 << 7), // small joystick left/right
MANUAL_MODE | (0 << 7) // small joystick up/down
};
void adcReadSPIDummy()
{
// A dummy command to get things started
// (because the sampled data is lagging behind for two command cycles)
ADC_CS_LOW();
delay_01us(1);
SPIx_ReadWriteByte(adcCommands[0]);
ADC_CS_HIGH();
delay_01us(1);
}
uint32_t adcReadNextSPIChannel(uint8_t index)
{
uint32_t result = 0;
// This delay is to allow charging of ADC input capacitor
// after the MUX changes from one channel to the other.
// It was determined experimentally. Biggest problem seems to be
// the cross-talk between A4:S1 and A5:MULTIPOS. Changing S1 for one extreme
// to the other resulted in A5 change of:
//
// delay value A5 change Time needed for adcRead()
// 1 16 0.154ms - 0.156ms
// 38 5 0.197ms - 0.199ms
// 62 0 0.225ms - 0.243ms
delay_01us(40);
for (uint8_t i = 0; i < 4; i++) {
ADC_CS_LOW();
delay_01us(1);
// command is changed to the next index for the last two readings
// (because the sampled data is lagging behind for two command cycles)
uint16_t val = (0x0fff & SPIx_ReadWriteByte(adcCommands[(i>1) ? index+1 : index]));
#if defined(JITTER_MEASURE)
if (JITTER_MEASURE_ACTIVE()) {
rawJitter[index].measure(val);
}
#endif
ADC_CS_HIGH();
delay_01us(1);
result += val;
}
return result >> 2;
}
void adcOnChipReadStart()
{
ADC_DMA_Stream->CR &= ~DMA_SxCR_EN; // Disable DMA
ADC3->SR &= ~(uint32_t)(ADC_SR_EOC | ADC_SR_STRT | ADC_SR_OVR);
ADC_DMA->LIFCR = DMA_LIFCR_CTCIF0 | DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0 | DMA_LIFCR_CFEIF0; // Write ones to clear bits
ADC_DMA_Stream->M0AR = CONVERT_PTR_UINT(&adcValues[MOUSE1]);
ADC_DMA_Stream->NDTR = 2;
ADC_DMA_Stream->CR |= DMA_SxCR_EN; // Enable DMA
ADC3->CR2 |= (uint32_t)ADC_CR2_SWSTART;
}
bool adcOnChipReadFinished()
{
return (ADC_DMA->LISR & DMA_LISR_TCIF0);
}
void adcRead()
{
uint16_t temp[NUM_ANALOGS-MOUSE1] = { 0 };
uint8_t noInternalReads = 0;
adcOnChipReadStart();
adcReadSPIDummy();
adcReadSPIDummy();
for (uint32_t index=0; index<MOUSE1; index++) {
adcValues[index] = adcReadNextSPIChannel(index);
if (noInternalReads < 4 && adcOnChipReadFinished()) {
for (uint8_t x=0; x<NUM_ANALOGS-MOUSE1; x++) {
uint16_t val = adcValues[MOUSE1+x];
#if defined(JITTER_MEASURE)
if (JITTER_MEASURE_ACTIVE()) {
rawJitter[MOUSE1+x].measure(val);
}
#endif
temp[x] += val;
}
if (++noInternalReads < 4) {
adcOnChipReadStart();
}
}
}
#if defined(DEBUG)
if (noInternalReads != 4) {
TRACE("Internal ADC problem: reads: %d", noInternalReads);
}
#endif
for (uint8_t x=0; x<NUM_ANALOGS-MOUSE1; x++) {
adcValues[MOUSE1+x] = temp[x] >> 2;
}
}
#if !defined(SIMU)
const int8_t ana_direction[NUM_ANALOGS] = {1,-1,1,-1, -1,1,-1, -1,-1, -1,1, 0,0,0};
uint16_t getAnalogValue(uint8_t index)
{
if (ana_direction[index] < 0)
return 4095 - adcValues[index];
else
return adcValues[index];
}
#endif // #if !defined(SIMU)

View file

@ -1,261 +1,261 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
Fifo<uint8_t, 64> btTxFifo;
Fifo<uint8_t, 64> btRxFifo;
enum BluetoothState
{
BLUETOOTH_INIT,
BLUETOOTH_WAIT_TTM,
BLUETOOTH_WAIT_BAUDRATE_CHANGE,
BLUETOOTH_OK,
};
enum BluetoothWriteState
{
BLUETOOTH_WRITE_IDLE,
BLUETOOTH_WRITE_INIT,
BLUETOOTH_WRITING,
BLUETOOTH_WRITE_DONE
};
volatile uint8_t bluetoothState = BLUETOOTH_INIT;
volatile uint8_t bluetoothWriteState = BLUETOOTH_WRITE_IDLE;
void bluetoothInit(uint32_t baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
USART_DeInit(BT_USART);
RCC_AHB1PeriphClockCmd(BT_RCC_AHB1Periph, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
GPIO_InitStructure.GPIO_Pin = BT_EN_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(BT_EN_GPIO, &GPIO_InitStructure);
#if defined(BT_BRTS_GPIO_PIN)
GPIO_InitStructure.GPIO_Pin = BT_BRTS_GPIO_PIN;
GPIO_Init(BT_BRTS_GPIO, &GPIO_InitStructure);
GPIO_SetBits(BT_BRTS_GPIO, BT_BRTS_GPIO_PIN);
#endif
#if defined(BT_BCTS_GPIO_PIN)
GPIO_InitStructure.GPIO_Pin = BT_BCTS_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(BT_BCTS_GPIO, &GPIO_InitStructure);
#endif
GPIO_InitStructure.GPIO_Pin = BT_TX_GPIO_PIN|BT_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(BT_GPIO_TXRX, &GPIO_InitStructure);
GPIO_PinAFConfig(BT_GPIO_TXRX, BT_TX_GPIO_PinSource, BT_GPIO_AF);
GPIO_PinAFConfig(BT_GPIO_TXRX, BT_RX_GPIO_PinSource, BT_GPIO_AF);
USART_DeInit(BT_USART);
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(BT_USART, &USART_InitStructure);
USART_Cmd(BT_USART, ENABLE);
USART_ITConfig(BT_USART, USART_IT_RXNE, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = BT_USART_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_ResetBits(BT_EN_GPIO, BT_EN_GPIO_PIN); // open bluetooth
}
void bluetoothDone()
{
GPIO_SetBits(BT_EN_GPIO, BT_EN_GPIO_PIN); // close bluetooth
}
extern "C" void USART6_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_BLUETOOTH);
if (USART_GetITStatus(BT_USART, USART_IT_RXNE) != RESET) {
USART_ClearITPendingBit(BT_USART, USART_IT_RXNE);
uint8_t byte = USART_ReceiveData(BT_USART);
btRxFifo.push(byte);
}
if (USART_GetITStatus(BT_USART, USART_IT_TXE) != RESET) {
uint8_t byte;
bool result = btTxFifo.pop(byte);
if (result) {
USART_SendData(BT_USART, byte);
}
else {
USART_ITConfig(BT_USART, USART_IT_TXE, DISABLE);
bluetoothWriteState = BLUETOOTH_WRITE_DONE;
}
}
}
void bluetoothWrite(const void * buffer, int len)
{
uint8_t * data = (uint8_t *)buffer;
for (int i=0; i<len; ++i) {
btTxFifo.push(data[i]);
}
}
void bluetoothWriteString(const char * str)
{
while (*str != 0) {
btTxFifo.push(*str++);
}
}
void bluetoothWriteWakeup(void)
{
if (bluetoothWriteState == BLUETOOTH_WRITE_IDLE) {
if (!btTxFifo.isEmpty()) {
bluetoothWriteState = BLUETOOTH_WRITE_INIT;
#if defined(BT_BRTS_GPIO_PIN)
GPIO_ResetBits(BT_BRTS_GPIO, BT_BRTS_GPIO_PIN);
#endif
}
}
else if (bluetoothWriteState == BLUETOOTH_WRITE_INIT) {
bluetoothWriteState = BLUETOOTH_WRITING;
USART_ITConfig(BT_USART, USART_IT_TXE, ENABLE);
}
else if (bluetoothWriteState == BLUETOOTH_WRITE_DONE) {
bluetoothWriteState = BLUETOOTH_WRITE_IDLE;
#if defined(BT_BRTS_GPIO_PIN)
GPIO_SetBits(BT_BRTS_GPIO, BT_BRTS_GPIO_PIN);
#endif
}
}
void bluetoothWakeup(void)
{
#if defined(BLUETOOTH_CLI_PASSTHROUGH)
bluetoothWriteWakeup();
return;
#else // #if defined(BLUETOOTH_CLI_PASSTHROUGH)
// NOTICE: code below doesn't work on Horus beta!
if (!g_eeGeneral.bluetoothEnable) {
if (bluetoothState != BLUETOOTH_INIT) {
bluetoothDone();
bluetoothState = BLUETOOTH_INIT;
}
}
else {
if (bluetoothState != BLUETOOTH_OK) {
static tmr10ms_t waitEnd = 0;
if (bluetoothState == BLUETOOTH_INIT) {
TRACE("BLUETOOTH_INIT");
bluetoothInit(BLUETOOTH_DEFAULT_BAUDRATE);
const char btMessage[] = "TTM:REN-";
bluetoothWriteString(btMessage);
uint8_t len = ZLEN(g_eeGeneral.bluetoothName);
for (int i=0; i<len; i++) {
btTxFifo.push(idx2char(g_eeGeneral.bluetoothName[i]));
}
bluetoothState = BLUETOOTH_WAIT_TTM;
waitEnd = get_tmr10ms() + 25; // 250ms
}
else if (bluetoothState == BLUETOOTH_WAIT_TTM) {
if (get_tmr10ms() > waitEnd) {
TRACE("bt rename");
char ttm[] = "TTM:REN";
int index = 0;
uint8_t c;
bool found = false;
while (btRxFifo.pop(c)) {
if (c == ttm[index]) {
index++;
if (index == sizeof(ttm)-1) {
found = true;
break;
}
}
else {
index = 0;
}
}
if (found) {
TRACE("bt OK");
bluetoothState = BLUETOOTH_OK;
}
else {
TRACE("bt failure");
bluetoothInit(BLUETOOTH_FACTORY_BAUDRATE);
const char btMessage[] = "TTM:BPS-115200";
bluetoothWriteString(btMessage);
bluetoothState = BLUETOOTH_WAIT_BAUDRATE_CHANGE;
waitEnd = get_tmr10ms() + 250; // 2.5s
}
}
}
else if (bluetoothState == BLUETOOTH_WAIT_BAUDRATE_CHANGE) {
if (get_tmr10ms() > waitEnd) {
bluetoothState = BLUETOOTH_INIT;
}
}
}
bluetoothWriteWakeup();
}
#endif // #if defined(BLUETOOTH_CLI_PASSTHROUGH)
}
uint8_t bluetoothReady()
{
return (bluetoothState == BLUETOOTH_OK);
}
int bluetoothRead(void * buffer, int len)
{
int result = 0;
uint8_t * data = (uint8_t *)buffer;
while (result < len) {
uint8_t byte;
if (!btRxFifo.pop(byte)) {
break;
}
data[result++] = byte;
}
return result;
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
Fifo<uint8_t, 64> btTxFifo;
Fifo<uint8_t, 64> btRxFifo;
enum BluetoothState
{
BLUETOOTH_INIT,
BLUETOOTH_WAIT_TTM,
BLUETOOTH_WAIT_BAUDRATE_CHANGE,
BLUETOOTH_OK,
};
enum BluetoothWriteState
{
BLUETOOTH_WRITE_IDLE,
BLUETOOTH_WRITE_INIT,
BLUETOOTH_WRITING,
BLUETOOTH_WRITE_DONE
};
volatile uint8_t bluetoothState = BLUETOOTH_INIT;
volatile uint8_t bluetoothWriteState = BLUETOOTH_WRITE_IDLE;
void bluetoothInit(uint32_t baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
USART_DeInit(BT_USART);
RCC_AHB1PeriphClockCmd(BT_RCC_AHB1Periph, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
GPIO_InitStructure.GPIO_Pin = BT_EN_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(BT_EN_GPIO, &GPIO_InitStructure);
#if defined(BT_BRTS_GPIO_PIN)
GPIO_InitStructure.GPIO_Pin = BT_BRTS_GPIO_PIN;
GPIO_Init(BT_BRTS_GPIO, &GPIO_InitStructure);
GPIO_SetBits(BT_BRTS_GPIO, BT_BRTS_GPIO_PIN);
#endif
#if defined(BT_BCTS_GPIO_PIN)
GPIO_InitStructure.GPIO_Pin = BT_BCTS_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(BT_BCTS_GPIO, &GPIO_InitStructure);
#endif
GPIO_InitStructure.GPIO_Pin = BT_TX_GPIO_PIN|BT_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(BT_GPIO_TXRX, &GPIO_InitStructure);
GPIO_PinAFConfig(BT_GPIO_TXRX, BT_TX_GPIO_PinSource, BT_GPIO_AF);
GPIO_PinAFConfig(BT_GPIO_TXRX, BT_RX_GPIO_PinSource, BT_GPIO_AF);
USART_DeInit(BT_USART);
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(BT_USART, &USART_InitStructure);
USART_Cmd(BT_USART, ENABLE);
USART_ITConfig(BT_USART, USART_IT_RXNE, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = BT_USART_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_ResetBits(BT_EN_GPIO, BT_EN_GPIO_PIN); // open bluetooth
}
void bluetoothDone()
{
GPIO_SetBits(BT_EN_GPIO, BT_EN_GPIO_PIN); // close bluetooth
}
extern "C" void USART6_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_BLUETOOTH);
if (USART_GetITStatus(BT_USART, USART_IT_RXNE) != RESET) {
USART_ClearITPendingBit(BT_USART, USART_IT_RXNE);
uint8_t byte = USART_ReceiveData(BT_USART);
btRxFifo.push(byte);
}
if (USART_GetITStatus(BT_USART, USART_IT_TXE) != RESET) {
uint8_t byte;
bool result = btTxFifo.pop(byte);
if (result) {
USART_SendData(BT_USART, byte);
}
else {
USART_ITConfig(BT_USART, USART_IT_TXE, DISABLE);
bluetoothWriteState = BLUETOOTH_WRITE_DONE;
}
}
}
void bluetoothWrite(const void * buffer, int len)
{
uint8_t * data = (uint8_t *)buffer;
for (int i=0; i<len; ++i) {
btTxFifo.push(data[i]);
}
}
void bluetoothWriteString(const char * str)
{
while (*str != 0) {
btTxFifo.push(*str++);
}
}
void bluetoothWriteWakeup(void)
{
if (bluetoothWriteState == BLUETOOTH_WRITE_IDLE) {
if (!btTxFifo.isEmpty()) {
bluetoothWriteState = BLUETOOTH_WRITE_INIT;
#if defined(BT_BRTS_GPIO_PIN)
GPIO_ResetBits(BT_BRTS_GPIO, BT_BRTS_GPIO_PIN);
#endif
}
}
else if (bluetoothWriteState == BLUETOOTH_WRITE_INIT) {
bluetoothWriteState = BLUETOOTH_WRITING;
USART_ITConfig(BT_USART, USART_IT_TXE, ENABLE);
}
else if (bluetoothWriteState == BLUETOOTH_WRITE_DONE) {
bluetoothWriteState = BLUETOOTH_WRITE_IDLE;
#if defined(BT_BRTS_GPIO_PIN)
GPIO_SetBits(BT_BRTS_GPIO, BT_BRTS_GPIO_PIN);
#endif
}
}
void bluetoothWakeup(void)
{
#if defined(BLUETOOTH_CLI_PASSTHROUGH)
bluetoothWriteWakeup();
return;
#else // #if defined(BLUETOOTH_CLI_PASSTHROUGH)
// NOTICE: code below doesn't work on Horus beta!
if (!g_eeGeneral.bluetoothEnable) {
if (bluetoothState != BLUETOOTH_INIT) {
bluetoothDone();
bluetoothState = BLUETOOTH_INIT;
}
}
else {
if (bluetoothState != BLUETOOTH_OK) {
static tmr10ms_t waitEnd = 0;
if (bluetoothState == BLUETOOTH_INIT) {
TRACE("BLUETOOTH_INIT");
bluetoothInit(BLUETOOTH_DEFAULT_BAUDRATE);
const char btMessage[] = "TTM:REN-";
bluetoothWriteString(btMessage);
uint8_t len = ZLEN(g_eeGeneral.bluetoothName);
for (int i=0; i<len; i++) {
btTxFifo.push(idx2char(g_eeGeneral.bluetoothName[i]));
}
bluetoothState = BLUETOOTH_WAIT_TTM;
waitEnd = get_tmr10ms() + 25; // 250ms
}
else if (bluetoothState == BLUETOOTH_WAIT_TTM) {
if (get_tmr10ms() > waitEnd) {
TRACE("bt rename");
char ttm[] = "TTM:REN";
int index = 0;
uint8_t c;
bool found = false;
while (btRxFifo.pop(c)) {
if (c == ttm[index]) {
index++;
if (index == sizeof(ttm)-1) {
found = true;
break;
}
}
else {
index = 0;
}
}
if (found) {
TRACE("bt OK");
bluetoothState = BLUETOOTH_OK;
}
else {
TRACE("bt failure");
bluetoothInit(BLUETOOTH_FACTORY_BAUDRATE);
const char btMessage[] = "TTM:BPS-115200";
bluetoothWriteString(btMessage);
bluetoothState = BLUETOOTH_WAIT_BAUDRATE_CHANGE;
waitEnd = get_tmr10ms() + 250; // 2.5s
}
}
}
else if (bluetoothState == BLUETOOTH_WAIT_BAUDRATE_CHANGE) {
if (get_tmr10ms() > waitEnd) {
bluetoothState = BLUETOOTH_INIT;
}
}
}
bluetoothWriteWakeup();
}
#endif // #if defined(BLUETOOTH_CLI_PASSTHROUGH)
}
uint8_t bluetoothReady()
{
return (bluetoothState == BLUETOOTH_OK);
}
int bluetoothRead(void * buffer, int len)
{
int result = 0;
uint8_t * data = (uint8_t *)buffer;
while (result < len) {
uint8_t byte;
if (!btRxFifo.pop(byte)) {
break;
}
data[result++] = byte;
}
return result;
}

View file

@ -1,376 +1,376 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "diskio.h"
#include <string.h>
#include "opentx.h"
#include "sdio_sd.h"
/*-----------------------------------------------------------------------*/
/* Lock / unlock functions */
/*-----------------------------------------------------------------------*/
#if !defined(BOOT)
static OS_MutexID ioMutex;
uint32_t ioMutexReq = 0, ioMutexRel = 0;
int ff_cre_syncobj (BYTE vol, _SYNC_t *mutex)
{
*mutex = ioMutex;
return 1;
}
int ff_req_grant (_SYNC_t mutex)
{
ioMutexReq += 1;
return CoEnterMutexSection(mutex) == E_OK;
}
void ff_rel_grant (_SYNC_t mutex)
{
ioMutexRel += 1;
CoLeaveMutexSection(mutex);
}
int ff_del_syncobj (_SYNC_t mutex)
{
return 1;
}
#endif
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0..) */
)
{
DSTATUS stat = 0;
/* Supports only single drive */
if (drv)
{
stat |= STA_NOINIT;
}
/*-------------------------- SD Init ----------------------------- */
SD_Error res = SD_Init();
if (res != SD_OK)
{
TRACE("SD_Init() failed: %d", res);
stat |= STA_NOINIT;
}
TRACE("SD card info:");
TRACE("sectors: %u", (uint32_t)(SDCardInfo.CardCapacity / 512));
TRACE("type: %u", (uint32_t)(SDCardInfo.CardType));
TRACE("EraseGrSize: %u", (uint32_t)(SDCardInfo.SD_csd.EraseGrSize));
TRACE("EraseGrMul: %u", (uint32_t)(SDCardInfo.SD_csd.EraseGrMul));
TRACE("ManufacturerID: %u", (uint32_t)(SDCardInfo.SD_cid.ManufacturerID));
return(stat);
}
DWORD scratch[BLOCK_SIZE / 4] __DMA;
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber (0..) */
)
{
DSTATUS stat = 0;
if (SD_Detect() != SD_PRESENT)
stat |= STA_NODISK;
// STA_NOTINIT - Subsystem not initailized
// STA_PROTECTED - Write protected, MMC/SD switch if available
return(stat);
}
uint32_t sdReadRetries = 0;
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read_dma(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
// this functions assumes that buff is properly aligned and in the right RAM segment for DMA
DRESULT res;
SD_Error Status;
SDTransferState State;
for (int retry=0; retry<3; retry++) {
res = RES_OK;
if (count == 1) {
Status = SD_ReadBlock(buff, sector, BLOCK_SIZE); // 4GB Compliant
}
else {
Status = SD_ReadMultiBlocks(buff, sector, BLOCK_SIZE, count); // 4GB Compliant
}
if (Status == SD_OK) {
Status = SD_WaitReadOperation(200*count); // Check if the Transfer is finished
while ((State = SD_GetStatus()) == SD_TRANSFER_BUSY); // BUSY, OK (DONE), ERROR (FAIL)
if (State == SD_TRANSFER_ERROR) {
TRACE("State=SD_TRANSFER_ERROR, c: %u", sector, (uint32_t)count);
res = RES_ERROR;
}
else if (Status != SD_OK) {
TRACE("Status(WaitRead)=%d, s:%u c: %u", Status, sector, (uint32_t)count);
res = RES_ERROR;
}
}
else {
TRACE("Status(ReadBlock)=%d, s:%u c: %u", Status, sector, (uint32_t)count);
res = RES_ERROR;
}
if (res == RES_OK) break;
sdReadRetries += 1;
}
return res;
}
DRESULT __disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
// If unaligned, do the single block reads with a scratch buffer.
// If aligned and single sector, do a single block read.
// If aligned and multiple sectors, try multi block read.
// If multi block read fails, try single block reads without
// an intermediate buffer (move trough the provided buffer)
// TRACE("disk_read %d %p %10d %d", drv, buff, sector, count);
if (SD_Detect() != SD_PRESENT) {
TRACE("SD_Detect() != SD_PRESENT");
return RES_NOTRDY;
}
DRESULT res = RES_OK;
if (count == 0) return res;
if ((DWORD)buff < 0x20000000 || ((DWORD)buff & 3)) {
// buffer is not aligned, use scratch buffer that is aligned
TRACE("disk_read bad alignment (%p)", buff);
while (count--) {
res = disk_read_dma(drv, (BYTE *)scratch, sector++, 1);
if (res != RES_OK) break;
memcpy(buff, scratch, BLOCK_SIZE);
buff += BLOCK_SIZE;
}
return res;
}
res = disk_read_dma(drv, buff, sector, count);
if (res != RES_OK && count > 1) {
// multi-read failed, try reading same sectors, one by one
TRACE("disk_read() multi-block failed, trying single block reads...");
while (count--) {
res = disk_read_dma(drv, buff, sector++, 1);
if (res != RES_OK) break;
buff += BLOCK_SIZE;
}
}
return res;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if _READONLY == 0
DRESULT __disk_write(
BYTE drv, /* Physical drive nmuber (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
UINT count /* Number of sectors to write (1..255) */
)
{
SD_Error Status;
DRESULT res = RES_OK;
// TRACE("disk_write %d %p %10d %d", drv, buff, sector, count);
if (SD_Detect() != SD_PRESENT)
return(RES_NOTRDY);
if ((DWORD)buff < 0x20000000 || ((DWORD)buff & 3)) {
TRACE("disk_write bad alignment (%p)", buff);
while(count--) {
memcpy(scratch, buff, BLOCK_SIZE);
res = __disk_write(drv, (BYTE *)scratch, sector++, 1);
if (res != RES_OK)
break;
buff += BLOCK_SIZE;
}
return(res);
}
if (count == 1) {
Status = SD_WriteBlock((uint8_t *)buff, sector, BLOCK_SIZE); // 4GB Compliant
}
else {
Status = SD_WriteMultiBlocks((uint8_t *)buff, sector, BLOCK_SIZE, count); // 4GB Compliant
}
if (Status == SD_OK) {
SDTransferState State;
Status = SD_WaitWriteOperation(500*count); // Check if the Transfer is finished
while((State = SD_GetStatus()) == SD_TRANSFER_BUSY); // BUSY, OK (DONE), ERROR (FAIL)
if ((State == SD_TRANSFER_ERROR) || (Status != SD_OK)) {
TRACE("__disk_write() err, st:%d,%d, s:%u c: %u", Status, State, sector, (uint32_t)count);
res = RES_ERROR;
}
}
else {
res = RES_ERROR;
}
// TRACE("result=%d", res);
return res;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
if (drv) return RES_PARERR;
res = RES_ERROR;
switch (ctrl) {
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
// use 512 for sector size, SDCardInfo.CardBlockSize is not sector size and can be 1024 for 2G SD cards!!!!
*(DWORD*)buff = SDCardInfo.CardCapacity / BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
*(WORD*)buff = BLOCK_SIZE; // force sector size. SDCardInfo.CardBlockSize is not sector size and can be 1024 for 2G SD cards!!!!
res = RES_OK;
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
// TODO verify that this is the correct value
*(DWORD*)buff = (uint32_t)SDCardInfo.SD_csd.EraseGrSize * (uint32_t)SDCardInfo.SD_csd.EraseGrMul;
res = RES_OK;
break;
case CTRL_SYNC:
while (SD_GetStatus() == SD_TRANSFER_BUSY); /* Complete pending write process (needed at _FS_READONLY == 0) */
res = RES_OK;
break;
default:
res = RES_OK;
break;
}
return res;
}
// TODO everything here should not be in the driver layer ...
FATFS g_FATFS_Obj __DMA; // initialized in boardInit()
#if defined(LOG_TELEMETRY)
FIL g_telemetryFile = {};
#endif
void sdInit()
{
TRACE("sdInit");
ioMutex = CoCreateMutex();
if (ioMutex >= CFG_MAX_MUTEX) {
// sd error
return;
}
sdMount();
}
void sdMount()
{
TRACE("sdMount");
diskCache.clear();
if (f_mount(&g_FATFS_Obj, "", 1) == FR_OK) {
// call sdGetFreeSectors() now because f_getfree() takes a long time first time it's called
sdGetFreeSectors();
#if defined(LOG_TELEMETRY)
f_open(&g_telemetryFile, LOGS_PATH "/telemetry.log", FA_OPEN_ALWAYS | FA_WRITE);
if (f_size(&g_telemetryFile) > 0) {
f_lseek(&g_telemetryFile, f_size(&g_telemetryFile)); // append
}
#endif
}
else {
TRACE("f_mount() failed");
}
}
void sdDone()
{
TRACE("sdDone");
if (sdMounted()) {
audioQueue.stopSD();
#if defined(LOG_TELEMETRY)
f_close(&g_telemetryFile);
#endif
f_mount(NULL, "", 0); // unmount SD
}
}
uint32_t sdMounted()
{
return g_FATFS_Obj.fs_type != 0;
}
uint32_t sdIsHC()
{
return true; // TODO (CardType & CT_BLOCK);
}
uint32_t sdGetSpeed()
{
return 330000;
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "diskio.h"
#include <string.h>
#include "opentx.h"
#include "sdio_sd.h"
/*-----------------------------------------------------------------------*/
/* Lock / unlock functions */
/*-----------------------------------------------------------------------*/
#if !defined(BOOT)
static OS_MutexID ioMutex;
uint32_t ioMutexReq = 0, ioMutexRel = 0;
int ff_cre_syncobj (BYTE vol, _SYNC_t *mutex)
{
*mutex = ioMutex;
return 1;
}
int ff_req_grant (_SYNC_t mutex)
{
ioMutexReq += 1;
return CoEnterMutexSection(mutex) == E_OK;
}
void ff_rel_grant (_SYNC_t mutex)
{
ioMutexRel += 1;
CoLeaveMutexSection(mutex);
}
int ff_del_syncobj (_SYNC_t mutex)
{
return 1;
}
#endif
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0..) */
)
{
DSTATUS stat = 0;
/* Supports only single drive */
if (drv)
{
stat |= STA_NOINIT;
}
/*-------------------------- SD Init ----------------------------- */
SD_Error res = SD_Init();
if (res != SD_OK)
{
TRACE("SD_Init() failed: %d", res);
stat |= STA_NOINIT;
}
TRACE("SD card info:");
TRACE("sectors: %u", (uint32_t)(SDCardInfo.CardCapacity / 512));
TRACE("type: %u", (uint32_t)(SDCardInfo.CardType));
TRACE("EraseGrSize: %u", (uint32_t)(SDCardInfo.SD_csd.EraseGrSize));
TRACE("EraseGrMul: %u", (uint32_t)(SDCardInfo.SD_csd.EraseGrMul));
TRACE("ManufacturerID: %u", (uint32_t)(SDCardInfo.SD_cid.ManufacturerID));
return(stat);
}
DWORD scratch[BLOCK_SIZE / 4] __DMA;
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber (0..) */
)
{
DSTATUS stat = 0;
if (SD_Detect() != SD_PRESENT)
stat |= STA_NODISK;
// STA_NOTINIT - Subsystem not initailized
// STA_PROTECTED - Write protected, MMC/SD switch if available
return(stat);
}
uint32_t sdReadRetries = 0;
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read_dma(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
// this functions assumes that buff is properly aligned and in the right RAM segment for DMA
DRESULT res;
SD_Error Status;
SDTransferState State;
for (int retry=0; retry<3; retry++) {
res = RES_OK;
if (count == 1) {
Status = SD_ReadBlock(buff, sector, BLOCK_SIZE); // 4GB Compliant
}
else {
Status = SD_ReadMultiBlocks(buff, sector, BLOCK_SIZE, count); // 4GB Compliant
}
if (Status == SD_OK) {
Status = SD_WaitReadOperation(200*count); // Check if the Transfer is finished
while ((State = SD_GetStatus()) == SD_TRANSFER_BUSY); // BUSY, OK (DONE), ERROR (FAIL)
if (State == SD_TRANSFER_ERROR) {
TRACE("State=SD_TRANSFER_ERROR, c: %u", sector, (uint32_t)count);
res = RES_ERROR;
}
else if (Status != SD_OK) {
TRACE("Status(WaitRead)=%d, s:%u c: %u", Status, sector, (uint32_t)count);
res = RES_ERROR;
}
}
else {
TRACE("Status(ReadBlock)=%d, s:%u c: %u", Status, sector, (uint32_t)count);
res = RES_ERROR;
}
if (res == RES_OK) break;
sdReadRetries += 1;
}
return res;
}
DRESULT __disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count)
{
// If unaligned, do the single block reads with a scratch buffer.
// If aligned and single sector, do a single block read.
// If aligned and multiple sectors, try multi block read.
// If multi block read fails, try single block reads without
// an intermediate buffer (move trough the provided buffer)
// TRACE("disk_read %d %p %10d %d", drv, buff, sector, count);
if (SD_Detect() != SD_PRESENT) {
TRACE("SD_Detect() != SD_PRESENT");
return RES_NOTRDY;
}
DRESULT res = RES_OK;
if (count == 0) return res;
if ((DWORD)buff < 0x20000000 || ((DWORD)buff & 3)) {
// buffer is not aligned, use scratch buffer that is aligned
TRACE("disk_read bad alignment (%p)", buff);
while (count--) {
res = disk_read_dma(drv, (BYTE *)scratch, sector++, 1);
if (res != RES_OK) break;
memcpy(buff, scratch, BLOCK_SIZE);
buff += BLOCK_SIZE;
}
return res;
}
res = disk_read_dma(drv, buff, sector, count);
if (res != RES_OK && count > 1) {
// multi-read failed, try reading same sectors, one by one
TRACE("disk_read() multi-block failed, trying single block reads...");
while (count--) {
res = disk_read_dma(drv, buff, sector++, 1);
if (res != RES_OK) break;
buff += BLOCK_SIZE;
}
}
return res;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if _READONLY == 0
DRESULT __disk_write(
BYTE drv, /* Physical drive nmuber (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
UINT count /* Number of sectors to write (1..255) */
)
{
SD_Error Status;
DRESULT res = RES_OK;
// TRACE("disk_write %d %p %10d %d", drv, buff, sector, count);
if (SD_Detect() != SD_PRESENT)
return(RES_NOTRDY);
if ((DWORD)buff < 0x20000000 || ((DWORD)buff & 3)) {
TRACE("disk_write bad alignment (%p)", buff);
while(count--) {
memcpy(scratch, buff, BLOCK_SIZE);
res = __disk_write(drv, (BYTE *)scratch, sector++, 1);
if (res != RES_OK)
break;
buff += BLOCK_SIZE;
}
return(res);
}
if (count == 1) {
Status = SD_WriteBlock((uint8_t *)buff, sector, BLOCK_SIZE); // 4GB Compliant
}
else {
Status = SD_WriteMultiBlocks((uint8_t *)buff, sector, BLOCK_SIZE, count); // 4GB Compliant
}
if (Status == SD_OK) {
SDTransferState State;
Status = SD_WaitWriteOperation(500*count); // Check if the Transfer is finished
while((State = SD_GetStatus()) == SD_TRANSFER_BUSY); // BUSY, OK (DONE), ERROR (FAIL)
if ((State == SD_TRANSFER_ERROR) || (Status != SD_OK)) {
TRACE("__disk_write() err, st:%d,%d, s:%u c: %u", Status, State, sector, (uint32_t)count);
res = RES_ERROR;
}
}
else {
res = RES_ERROR;
}
// TRACE("result=%d", res);
return res;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
if (drv) return RES_PARERR;
res = RES_ERROR;
switch (ctrl) {
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
// use 512 for sector size, SDCardInfo.CardBlockSize is not sector size and can be 1024 for 2G SD cards!!!!
*(DWORD*)buff = SDCardInfo.CardCapacity / BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
*(WORD*)buff = BLOCK_SIZE; // force sector size. SDCardInfo.CardBlockSize is not sector size and can be 1024 for 2G SD cards!!!!
res = RES_OK;
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
// TODO verify that this is the correct value
*(DWORD*)buff = (uint32_t)SDCardInfo.SD_csd.EraseGrSize * (uint32_t)SDCardInfo.SD_csd.EraseGrMul;
res = RES_OK;
break;
case CTRL_SYNC:
while (SD_GetStatus() == SD_TRANSFER_BUSY); /* Complete pending write process (needed at _FS_READONLY == 0) */
res = RES_OK;
break;
default:
res = RES_OK;
break;
}
return res;
}
// TODO everything here should not be in the driver layer ...
FATFS g_FATFS_Obj __DMA; // initialized in boardInit()
#if defined(LOG_TELEMETRY)
FIL g_telemetryFile = {};
#endif
void sdInit()
{
TRACE("sdInit");
ioMutex = CoCreateMutex();
if (ioMutex >= CFG_MAX_MUTEX) {
// sd error
return;
}
sdMount();
}
void sdMount()
{
TRACE("sdMount");
diskCache.clear();
if (f_mount(&g_FATFS_Obj, "", 1) == FR_OK) {
// call sdGetFreeSectors() now because f_getfree() takes a long time first time it's called
sdGetFreeSectors();
#if defined(LOG_TELEMETRY)
f_open(&g_telemetryFile, LOGS_PATH "/telemetry.log", FA_OPEN_ALWAYS | FA_WRITE);
if (f_size(&g_telemetryFile) > 0) {
f_lseek(&g_telemetryFile, f_size(&g_telemetryFile)); // append
}
#endif
}
else {
TRACE("f_mount() failed");
}
}
void sdDone()
{
TRACE("sdDone");
if (sdMounted()) {
audioQueue.stopSD();
#if defined(LOG_TELEMETRY)
f_close(&g_telemetryFile);
#endif
f_mount(NULL, "", 0); // unmount SD
}
}
uint32_t sdMounted()
{
return g_FATFS_Obj.fs_type != 0;
}
uint32_t sdIsHC()
{
return true; // TODO (CardType & CT_BLOCK);
}
uint32_t sdGetSpeed()
{
return 330000;
}

View file

@ -1,309 +1,309 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void extmoduleSendNextFrame();
void extmoduleStop()
{
EXTERNAL_MODULE_OFF();
NVIC_DisableIRQ(EXTMODULE_DMA_IRQn);
NVIC_DisableIRQ(EXTMODULE_TIMER_IRQn);
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_TIMER->DIER &= ~(TIM_DIER_CC2IE | TIM_DIER_UDE);
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
}
void extmoduleNoneStart()
{
EXTERNAL_MODULE_OFF();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, 0);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
GPIO_SetBits(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PIN); // Set high
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = 36000; // 18mS
EXTMODULE_TIMER->CCR2 = 32000; // Update time
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF;
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
void extmodulePpmStart()
{
EXTERNAL_MODULE_ON();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, EXTMODULE_PPM_GPIO_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
// PPM generation principle:
//
// Hardware timer in PWM mode is used for PPM generation
// Output is OFF if CNT<CCR1(delay) and ON if bigger
// CCR1 register defines duration of pulse length and is constant
// AAR register defines duration of each pulse, it is
// updated after every pulse in Update interrupt handler.
// CCR2 register defines duration of no pulses (time between two pulse trains)
// it is calculated every round to have PPM period constant.
// CC2 interrupt is then used to setup new PPM values for the
// next PPM pulses train.
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop timer
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = 45000;
#if PCBREV >= 13
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2; // PWM mode 1
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE;
EXTMODULE_TIMER->EGR = 1; // Reloads register values now
EXTMODULE_TIMER->DIER = TIM_DIER_UDE; // Update DMA request
EXTMODULE_TIMER->CR1 = TIM_CR1_CEN; // Start timer
#else
EXTMODULE_TIMER->CCR1 = GET_PPM_DELAY(EXTERNAL_MODULE)*2;
EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | (GET_PPM_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0);
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Reloads register values now
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Update DMA request
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC2PE; // PWM mode 1
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; // Start timer
#endif
extmoduleSendNextFrame();
NVIC_EnableIRQ(EXTMODULE_DMA_IRQn);
NVIC_SetPriority(EXTMODULE_DMA_IRQn, 7);
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
void extmodulePxxStart()
{
EXTERNAL_MODULE_ON();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, EXTMODULE_PPM_GPIO_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = 18000;
#if PCBREV >= 13
EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | TIM_CCER_CC3NE;
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR3 = 18;
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
#else
EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC1NE | TIM_CCER_CC1NP; // TIM_CCER_CC1E | TIM_CCER_CC1P;
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR1 = 18;
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
#endif
extmoduleSendNextFrame();
NVIC_EnableIRQ(EXTMODULE_DMA_IRQn);
NVIC_SetPriority(EXTMODULE_DMA_IRQn, 7);
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
#if defined(DSM2)
void extmoduleDsm2Start()
{
EXTERNAL_MODULE_ON();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, EXTMODULE_PPM_GPIO_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = 44000; // 22mS
#if PCBREV >= 13
EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | TIM_CCER_CC3P;
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR3 = 0;
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
#else
EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P;
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR1 = 0;
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
#endif
extmoduleSendNextFrame();
NVIC_EnableIRQ(EXTMODULE_DMA_IRQn);
NVIC_SetPriority(EXTMODULE_DMA_IRQn, 7);
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
#endif
void extmoduleCrossfireStart()
{
EXTERNAL_MODULE_ON();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, 0);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
GPIO_SetBits(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PIN); // Set high
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = (2000 * CROSSFIRE_FRAME_PERIOD);
EXTMODULE_TIMER->CCR2 = (2000 * CROSSFIRE_FRAME_PERIOD) - 1000;
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF;
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
void extmoduleSendNextFrame()
{
if (s_current_protocol[EXTERNAL_MODULE] == PROTO_PPM) {
#if PCBREV >= 13
EXTMODULE_TIMER->CCR3 = GET_PPM_DELAY(EXTERNAL_MODULE)*2;
EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | (GET_PPM_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0);
EXTMODULE_TIMER->CCR2 = *(modulePulsesData[EXTERNAL_MODULE].ppm.ptr - 1) - 4000; // 2mS in advance
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#else
EXTMODULE_TIMER->CCR1 = GET_PPM_DELAY(EXTERNAL_MODULE)*2;
EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | (GET_PPM_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0);
EXTMODULE_TIMER->CCR2 = *(modulePulsesData[EXTERNAL_MODULE].ppm.ptr - 1) - 4000; // 2mS in advance
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#endif
EXTMODULE_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_DMA_STREAM->M0AR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].ppm.pulses);
EXTMODULE_DMA_STREAM->NDTR = modulePulsesData[EXTERNAL_MODULE].ppm.ptr - modulePulsesData[EXTERNAL_MODULE].ppm.pulses;
EXTMODULE_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
}
else if (s_current_protocol[EXTERNAL_MODULE] == PROTO_PXX) {
EXTMODULE_TIMER->CCR2 = *(modulePulsesData[EXTERNAL_MODULE].pxx.ptr - 1) - 4000; // 2mS in advance
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
#if PCBREV >= 13
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#else
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#endif
EXTMODULE_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_DMA_STREAM->M0AR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].pxx.pulses);
EXTMODULE_DMA_STREAM->NDTR = modulePulsesData[EXTERNAL_MODULE].pxx.ptr - modulePulsesData[EXTERNAL_MODULE].pxx.pulses;
EXTMODULE_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
}
else if (IS_DSM2_PROTOCOL(s_current_protocol[EXTERNAL_MODULE]) || IS_MULTIMODULE_PROTOCOL(s_current_protocol[EXTERNAL_MODULE])) {
EXTMODULE_TIMER->CCR2 = *(modulePulsesData[EXTERNAL_MODULE].dsm2.ptr - 1) - 4000; // 2mS in advance
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
#if PCBREV >= 13
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#else
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#endif
EXTMODULE_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_DMA_STREAM->M0AR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].dsm2.pulses);
EXTMODULE_DMA_STREAM->NDTR = modulePulsesData[EXTERNAL_MODULE].dsm2.ptr - modulePulsesData[EXTERNAL_MODULE].dsm2.pulses;
EXTMODULE_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
}
else {
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE;
}
}
extern "C" void EXTMODULE_DMA_IRQHandler()
{
if (!DMA_GetITStatus(EXTMODULE_DMA_STREAM, EXTMODULE_DMA_FLAG_TC))
return;
DMA_ClearITPendingBit(EXTMODULE_DMA_STREAM, EXTMODULE_DMA_FLAG_TC);
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
}
extern "C" void EXTMODULE_TIMER_IRQHandler()
{
EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF;
setupPulses(EXTERNAL_MODULE);
extmoduleSendNextFrame();
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void extmoduleSendNextFrame();
void extmoduleStop()
{
EXTERNAL_MODULE_OFF();
NVIC_DisableIRQ(EXTMODULE_DMA_IRQn);
NVIC_DisableIRQ(EXTMODULE_TIMER_IRQn);
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_TIMER->DIER &= ~(TIM_DIER_CC2IE | TIM_DIER_UDE);
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
}
void extmoduleNoneStart()
{
EXTERNAL_MODULE_OFF();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, 0);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
GPIO_SetBits(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PIN); // Set high
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = 36000; // 18mS
EXTMODULE_TIMER->CCR2 = 32000; // Update time
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF;
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
void extmodulePpmStart()
{
EXTERNAL_MODULE_ON();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, EXTMODULE_PPM_GPIO_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
// PPM generation principle:
//
// Hardware timer in PWM mode is used for PPM generation
// Output is OFF if CNT<CCR1(delay) and ON if bigger
// CCR1 register defines duration of pulse length and is constant
// AAR register defines duration of each pulse, it is
// updated after every pulse in Update interrupt handler.
// CCR2 register defines duration of no pulses (time between two pulse trains)
// it is calculated every round to have PPM period constant.
// CC2 interrupt is then used to setup new PPM values for the
// next PPM pulses train.
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop timer
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = 45000;
#if PCBREV >= 13
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2; // PWM mode 1
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE;
EXTMODULE_TIMER->EGR = 1; // Reloads register values now
EXTMODULE_TIMER->DIER = TIM_DIER_UDE; // Update DMA request
EXTMODULE_TIMER->CR1 = TIM_CR1_CEN; // Start timer
#else
EXTMODULE_TIMER->CCR1 = GET_PPM_DELAY(EXTERNAL_MODULE)*2;
EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | (GET_PPM_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0);
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Reloads register values now
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Update DMA request
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC2PE; // PWM mode 1
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; // Start timer
#endif
extmoduleSendNextFrame();
NVIC_EnableIRQ(EXTMODULE_DMA_IRQn);
NVIC_SetPriority(EXTMODULE_DMA_IRQn, 7);
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
void extmodulePxxStart()
{
EXTERNAL_MODULE_ON();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, EXTMODULE_PPM_GPIO_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = 18000;
#if PCBREV >= 13
EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | TIM_CCER_CC3NE;
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR3 = 18;
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
#else
EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC1NE | TIM_CCER_CC1NP; // TIM_CCER_CC1E | TIM_CCER_CC1P;
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR1 = 18;
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
#endif
extmoduleSendNextFrame();
NVIC_EnableIRQ(EXTMODULE_DMA_IRQn);
NVIC_SetPriority(EXTMODULE_DMA_IRQn, 7);
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
#if defined(DSM2)
void extmoduleDsm2Start()
{
EXTERNAL_MODULE_ON();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, EXTMODULE_PPM_GPIO_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = 44000; // 22mS
#if PCBREV >= 13
EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | TIM_CCER_CC3P;
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR3 = 0;
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
EXTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
#else
EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P;
EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs
EXTMODULE_TIMER->CCR1 = 0;
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update
EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0;
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
#endif
extmoduleSendNextFrame();
NVIC_EnableIRQ(EXTMODULE_DMA_IRQn);
NVIC_SetPriority(EXTMODULE_DMA_IRQn, 7);
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
#endif
void extmoduleCrossfireStart()
{
EXTERNAL_MODULE_ON();
GPIO_PinAFConfig(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PinSource, 0);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PPM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(EXTMODULE_PPM_GPIO, &GPIO_InitStructure);
GPIO_SetBits(EXTMODULE_PPM_GPIO, EXTMODULE_PPM_GPIO_PIN); // Set high
EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
EXTMODULE_TIMER->ARR = (2000 * CROSSFIRE_FRAME_PERIOD);
EXTMODULE_TIMER->CCR2 = (2000 * CROSSFIRE_FRAME_PERIOD) - 1000;
EXTMODULE_TIMER->EGR = 1; // Restart
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF;
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(EXTMODULE_TIMER_IRQn);
NVIC_SetPriority(EXTMODULE_TIMER_IRQn, 7);
}
void extmoduleSendNextFrame()
{
if (s_current_protocol[EXTERNAL_MODULE] == PROTO_PPM) {
#if PCBREV >= 13
EXTMODULE_TIMER->CCR3 = GET_PPM_DELAY(EXTERNAL_MODULE)*2;
EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | (GET_PPM_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0);
EXTMODULE_TIMER->CCR2 = *(modulePulsesData[EXTERNAL_MODULE].ppm.ptr - 1) - 4000; // 2mS in advance
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#else
EXTMODULE_TIMER->CCR1 = GET_PPM_DELAY(EXTERNAL_MODULE)*2;
EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | (GET_PPM_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0);
EXTMODULE_TIMER->CCR2 = *(modulePulsesData[EXTERNAL_MODULE].ppm.ptr - 1) - 4000; // 2mS in advance
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#endif
EXTMODULE_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_DMA_STREAM->M0AR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].ppm.pulses);
EXTMODULE_DMA_STREAM->NDTR = modulePulsesData[EXTERNAL_MODULE].ppm.ptr - modulePulsesData[EXTERNAL_MODULE].ppm.pulses;
EXTMODULE_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
}
else if (s_current_protocol[EXTERNAL_MODULE] == PROTO_PXX) {
EXTMODULE_TIMER->CCR2 = *(modulePulsesData[EXTERNAL_MODULE].pxx.ptr - 1) - 4000; // 2mS in advance
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
#if PCBREV >= 13
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#else
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#endif
EXTMODULE_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_DMA_STREAM->M0AR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].pxx.pulses);
EXTMODULE_DMA_STREAM->NDTR = modulePulsesData[EXTERNAL_MODULE].pxx.ptr - modulePulsesData[EXTERNAL_MODULE].pxx.pulses;
EXTMODULE_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
}
else if (IS_DSM2_PROTOCOL(s_current_protocol[EXTERNAL_MODULE]) || IS_MULTIMODULE_PROTOCOL(s_current_protocol[EXTERNAL_MODULE])) {
EXTMODULE_TIMER->CCR2 = *(modulePulsesData[EXTERNAL_MODULE].dsm2.ptr - 1) - 4000; // 2mS in advance
EXTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
#if PCBREV >= 13
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#else
EXTMODULE_DMA_STREAM->CR |= EXTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
#endif
EXTMODULE_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_DMA_STREAM->M0AR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].dsm2.pulses);
EXTMODULE_DMA_STREAM->NDTR = modulePulsesData[EXTERNAL_MODULE].dsm2.ptr - modulePulsesData[EXTERNAL_MODULE].dsm2.pulses;
EXTMODULE_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
}
else {
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE;
}
}
extern "C" void EXTMODULE_DMA_IRQHandler()
{
if (!DMA_GetITStatus(EXTMODULE_DMA_STREAM, EXTMODULE_DMA_FLAG_TC))
return;
DMA_ClearITPendingBit(EXTMODULE_DMA_STREAM, EXTMODULE_DMA_FLAG_TC);
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
}
extern "C" void EXTMODULE_TIMER_IRQHandler()
{
EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt
EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF;
setupPulses(EXTERNAL_MODULE);
extmoduleSendNextFrame();
}

File diff suppressed because it is too large Load diff

View file

@ -1,217 +1,217 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint32_t rotencPosition;
uint32_t readKeys()
{
uint32_t result = 0;
#if defined(PCBX12S)
if (~KEYS_GPIO_REG_PGUP & KEYS_GPIO_PIN_PGUP)
result |= 1 << KEY_PGUP;
#endif
if (~KEYS_GPIO_REG_PGDN & KEYS_GPIO_PIN_PGDN)
result |= 1 << KEY_PGDN;
if (~KEYS_GPIO_REG_ENTER & KEYS_GPIO_PIN_ENTER)
result |= 1 << KEY_ENTER;
if (~KEYS_GPIO_REG_UP & KEYS_GPIO_PIN_UP)
result |= 1 << KEY_MODEL;
if (~KEYS_GPIO_REG_DOWN & KEYS_GPIO_PIN_DOWN)
result |= 1 << KEY_EXIT;
if (~KEYS_GPIO_REG_RIGHT & KEYS_GPIO_PIN_RIGHT)
result |= 1 << KEY_TELEM;
if (~KEYS_GPIO_REG_LEFT & KEYS_GPIO_PIN_LEFT)
result |= 1 << KEY_RADIO;
// TRACE("readKeys(): %x", result);
return result;
}
uint32_t readTrims()
{
uint32_t result = 0;
if (~TRIMS_GPIO_REG_LHL & TRIMS_GPIO_PIN_LHL)
result |= 0x01;
if (~TRIMS_GPIO_REG_LHR & TRIMS_GPIO_PIN_LHR)
result |= 0x02;
if (~TRIMS_GPIO_REG_LVD & TRIMS_GPIO_PIN_LVD)
result |= 0x04;
if (~TRIMS_GPIO_REG_LVU & TRIMS_GPIO_PIN_LVU)
result |= 0x08;
if (~TRIMS_GPIO_REG_RVD & TRIMS_GPIO_PIN_RVD)
result |= 0x10;
if (~TRIMS_GPIO_REG_RVU & TRIMS_GPIO_PIN_RVU)
result |= 0x20;
if (~TRIMS_GPIO_REG_RHL & TRIMS_GPIO_PIN_RHL)
result |= 0x40;
if (~TRIMS_GPIO_REG_RHR & TRIMS_GPIO_PIN_RHR)
result |= 0x80;
if (~TRIMS_GPIO_REG_LSD & TRIMS_GPIO_PIN_LSD)
result |= 0x100;
if (~TRIMS_GPIO_REG_LSU & TRIMS_GPIO_PIN_LSU)
result |= 0x200;
if (~TRIMS_GPIO_REG_RSD & TRIMS_GPIO_PIN_RSD)
result |= 0x400;
if (~TRIMS_GPIO_REG_RSU & TRIMS_GPIO_PIN_RSU)
result |= 0x800;
// TRACE("readTrims(): result=0x%04x", result);
return result;
}
uint16_t trimDown(uint16_t idx)
{
return readTrims() & (1 << idx);
}
uint8_t keyDown()
{
return readKeys();
}
void checkRotaryEncoder()
{
uint32_t newpos = ROTARY_ENCODER_POSITION();
if (newpos != rotencPosition && !keyState(KEY_ENTER)) {
if ((rotencPosition & 0x01) ^ ((newpos & 0x02) >> 1)) {
--rotencValue[0];
}
else {
++rotencValue[0];
}
rotencPosition = newpos;
}
}
/* TODO common to ARM */
void readKeysAndTrims()
{
uint32_t i;
uint8_t index = 0;
uint32_t in = readKeys();
for (i = 0; i < TRM_BASE; i++) {
keys[index++].input(in & (1 << i));
}
in = readTrims();
for (i = 1; i <= 1 << (TRM_LAST-TRM_BASE); i <<= 1) {
keys[index++].input(in & i);
}
}
#define ADD_2POS_CASE(x) \
case SW_S ## x ## 0: \
xxx = SWITCHES_GPIO_REG_ ## x & SWITCHES_GPIO_PIN_ ## x ; \
break; \
case SW_S ## x ## 2: \
xxx = ~SWITCHES_GPIO_REG_ ## x & SWITCHES_GPIO_PIN_ ## x ; \
break
#define ADD_NEG_2POS_CASE(x) \
case SW_S ## x ## 2: \
xxx = SWITCHES_GPIO_REG_ ## x & SWITCHES_GPIO_PIN_ ## x ; \
break; \
case SW_S ## x ## 0: \
xxx = ~SWITCHES_GPIO_REG_ ## x & SWITCHES_GPIO_PIN_ ## x ; \
break
#define ADD_3POS_CASE(x, i) \
case SW_S ## x ## 0: \
xxx = (SWITCHES_GPIO_REG_ ## x ## _H & SWITCHES_GPIO_PIN_ ## x ## _H); \
if (IS_3POS(i)) { \
xxx = xxx && (~SWITCHES_GPIO_REG_ ## x ## _L & SWITCHES_GPIO_PIN_ ## x ## _L); \
} \
break; \
case SW_S ## x ## 1: \
xxx = (SWITCHES_GPIO_REG_ ## x ## _H & SWITCHES_GPIO_PIN_ ## x ## _H) && (SWITCHES_GPIO_REG_ ## x ## _L & SWITCHES_GPIO_PIN_ ## x ## _L); \
break; \
case SW_S ## x ## 2: \
xxx = (~SWITCHES_GPIO_REG_ ## x ## _H & SWITCHES_GPIO_PIN_ ## x ## _H); \
if (IS_3POS(i)) { \
xxx = xxx && (SWITCHES_GPIO_REG_ ## x ## _L & SWITCHES_GPIO_PIN_ ## x ## _L); \
} \
break
#if !defined(BOOT)
uint8_t keyState(uint8_t index)
{
return keys[index].state();
}
uint32_t switchState(uint8_t index)
{
uint32_t xxx = 0;
switch (index) {
ADD_3POS_CASE(A, 0);
ADD_3POS_CASE(B, 1);
ADD_3POS_CASE(C, 2);
ADD_3POS_CASE(D, 3);
ADD_3POS_CASE(E, 4);
ADD_NEG_2POS_CASE(F);
ADD_3POS_CASE(G, 6);
ADD_2POS_CASE(H);
default:
break;
}
// TRACE("switch %d => %d", index, xxx);
return xxx;
}
#endif
void keysInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOB_PINS;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOC_PINS;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOD_PINS;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOE_PINS;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOG_PINS;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOH_PINS;
GPIO_Init(GPIOH, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOI_PINS;
GPIO_Init(GPIOI, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOJ_PINS;
GPIO_Init(GPIOJ, &GPIO_InitStructure);
rotencPosition = ROTARY_ENCODER_POSITION();
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint32_t rotencPosition;
uint32_t readKeys()
{
uint32_t result = 0;
#if defined(PCBX12S)
if (~KEYS_GPIO_REG_PGUP & KEYS_GPIO_PIN_PGUP)
result |= 1 << KEY_PGUP;
#endif
if (~KEYS_GPIO_REG_PGDN & KEYS_GPIO_PIN_PGDN)
result |= 1 << KEY_PGDN;
if (~KEYS_GPIO_REG_ENTER & KEYS_GPIO_PIN_ENTER)
result |= 1 << KEY_ENTER;
if (~KEYS_GPIO_REG_UP & KEYS_GPIO_PIN_UP)
result |= 1 << KEY_MODEL;
if (~KEYS_GPIO_REG_DOWN & KEYS_GPIO_PIN_DOWN)
result |= 1 << KEY_EXIT;
if (~KEYS_GPIO_REG_RIGHT & KEYS_GPIO_PIN_RIGHT)
result |= 1 << KEY_TELEM;
if (~KEYS_GPIO_REG_LEFT & KEYS_GPIO_PIN_LEFT)
result |= 1 << KEY_RADIO;
// TRACE("readKeys(): %x", result);
return result;
}
uint32_t readTrims()
{
uint32_t result = 0;
if (~TRIMS_GPIO_REG_LHL & TRIMS_GPIO_PIN_LHL)
result |= 0x01;
if (~TRIMS_GPIO_REG_LHR & TRIMS_GPIO_PIN_LHR)
result |= 0x02;
if (~TRIMS_GPIO_REG_LVD & TRIMS_GPIO_PIN_LVD)
result |= 0x04;
if (~TRIMS_GPIO_REG_LVU & TRIMS_GPIO_PIN_LVU)
result |= 0x08;
if (~TRIMS_GPIO_REG_RVD & TRIMS_GPIO_PIN_RVD)
result |= 0x10;
if (~TRIMS_GPIO_REG_RVU & TRIMS_GPIO_PIN_RVU)
result |= 0x20;
if (~TRIMS_GPIO_REG_RHL & TRIMS_GPIO_PIN_RHL)
result |= 0x40;
if (~TRIMS_GPIO_REG_RHR & TRIMS_GPIO_PIN_RHR)
result |= 0x80;
if (~TRIMS_GPIO_REG_LSD & TRIMS_GPIO_PIN_LSD)
result |= 0x100;
if (~TRIMS_GPIO_REG_LSU & TRIMS_GPIO_PIN_LSU)
result |= 0x200;
if (~TRIMS_GPIO_REG_RSD & TRIMS_GPIO_PIN_RSD)
result |= 0x400;
if (~TRIMS_GPIO_REG_RSU & TRIMS_GPIO_PIN_RSU)
result |= 0x800;
// TRACE("readTrims(): result=0x%04x", result);
return result;
}
uint16_t trimDown(uint16_t idx)
{
return readTrims() & (1 << idx);
}
uint8_t keyDown()
{
return readKeys();
}
void checkRotaryEncoder()
{
uint32_t newpos = ROTARY_ENCODER_POSITION();
if (newpos != rotencPosition && !keyState(KEY_ENTER)) {
if ((rotencPosition & 0x01) ^ ((newpos & 0x02) >> 1)) {
--rotencValue[0];
}
else {
++rotencValue[0];
}
rotencPosition = newpos;
}
}
/* TODO common to ARM */
void readKeysAndTrims()
{
uint32_t i;
uint8_t index = 0;
uint32_t in = readKeys();
for (i = 0; i < TRM_BASE; i++) {
keys[index++].input(in & (1 << i));
}
in = readTrims();
for (i = 1; i <= 1 << (TRM_LAST-TRM_BASE); i <<= 1) {
keys[index++].input(in & i);
}
}
#define ADD_2POS_CASE(x) \
case SW_S ## x ## 0: \
xxx = SWITCHES_GPIO_REG_ ## x & SWITCHES_GPIO_PIN_ ## x ; \
break; \
case SW_S ## x ## 2: \
xxx = ~SWITCHES_GPIO_REG_ ## x & SWITCHES_GPIO_PIN_ ## x ; \
break
#define ADD_NEG_2POS_CASE(x) \
case SW_S ## x ## 2: \
xxx = SWITCHES_GPIO_REG_ ## x & SWITCHES_GPIO_PIN_ ## x ; \
break; \
case SW_S ## x ## 0: \
xxx = ~SWITCHES_GPIO_REG_ ## x & SWITCHES_GPIO_PIN_ ## x ; \
break
#define ADD_3POS_CASE(x, i) \
case SW_S ## x ## 0: \
xxx = (SWITCHES_GPIO_REG_ ## x ## _H & SWITCHES_GPIO_PIN_ ## x ## _H); \
if (IS_3POS(i)) { \
xxx = xxx && (~SWITCHES_GPIO_REG_ ## x ## _L & SWITCHES_GPIO_PIN_ ## x ## _L); \
} \
break; \
case SW_S ## x ## 1: \
xxx = (SWITCHES_GPIO_REG_ ## x ## _H & SWITCHES_GPIO_PIN_ ## x ## _H) && (SWITCHES_GPIO_REG_ ## x ## _L & SWITCHES_GPIO_PIN_ ## x ## _L); \
break; \
case SW_S ## x ## 2: \
xxx = (~SWITCHES_GPIO_REG_ ## x ## _H & SWITCHES_GPIO_PIN_ ## x ## _H); \
if (IS_3POS(i)) { \
xxx = xxx && (SWITCHES_GPIO_REG_ ## x ## _L & SWITCHES_GPIO_PIN_ ## x ## _L); \
} \
break
#if !defined(BOOT)
uint8_t keyState(uint8_t index)
{
return keys[index].state();
}
uint32_t switchState(uint8_t index)
{
uint32_t xxx = 0;
switch (index) {
ADD_3POS_CASE(A, 0);
ADD_3POS_CASE(B, 1);
ADD_3POS_CASE(C, 2);
ADD_3POS_CASE(D, 3);
ADD_3POS_CASE(E, 4);
ADD_NEG_2POS_CASE(F);
ADD_3POS_CASE(G, 6);
ADD_2POS_CASE(H);
default:
break;
}
// TRACE("switch %d => %d", index, xxx);
return xxx;
}
#endif
void keysInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOB_PINS;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOC_PINS;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOD_PINS;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOE_PINS;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOG_PINS;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOH_PINS;
GPIO_Init(GPIOH, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOI_PINS;
GPIO_Init(GPIOI, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOJ_PINS;
GPIO_Init(GPIOJ, &GPIO_InitStructure);
rotencPosition = ROTARY_ENCODER_POSITION();
}

File diff suppressed because it is too large Load diff

View file

@ -1,270 +1,270 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void intmoduleStop(void);
void extmoduleStop(void);
void intmoduleNoneStart(void);
void intmodulePxxStart(void);
void extmoduleNoneStart(void);
void extmodulePpmStart(void);
void extmodulePxxStart(void);
#if defined(DSM2)
void extmoduleDsm2Start(void);
#endif
void extmoduleCrossfireStart(void);
void init_no_pulses(uint32_t port)
{
if (port == INTERNAL_MODULE)
intmoduleNoneStart();
else
extmoduleNoneStart();
}
void disable_no_pulses(uint32_t port)
{
if (port == INTERNAL_MODULE)
intmoduleStop();
else
extmoduleStop();
}
void init_ppm(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmodulePpmStart();
}
}
void disable_ppm(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleStop();
}
}
void init_pxx(uint32_t port)
{
if (port == INTERNAL_MODULE)
intmodulePxxStart();
else
extmodulePxxStart();
}
void disable_pxx(uint32_t port)
{
if (port == INTERNAL_MODULE)
intmoduleStop();
else
extmoduleStop();
}
#if defined(DSM2)
void init_dsm2(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleDsm2Start();
}
}
void disable_dsm2(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleStop();
}
}
#endif
#if defined(MULTIMODULE)
void init_multimodule(uint32_t port)
{
init_dsm2(port);
}
void disable_multimodule(uint32_t port)
{
disable_dsm2(port);
}
#endif
void init_crossfire(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleCrossfireStart();
}
}
void disable_crossfire(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleStop();
}
}
void intmoduleStop()
{
INTERNAL_MODULE_OFF();
NVIC_DisableIRQ(INTMODULE_TIMER_IRQn);
INTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE;
INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
}
void intmoduleNoneStart()
{
INTERNAL_MODULE_OFF();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = INTMODULE_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(INTMODULE_TX_GPIO, &GPIO_InitStructure);
GPIO_SetBits(INTMODULE_TX_GPIO, INTMODULE_TX_GPIO_PIN); // Set high
INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
INTMODULE_TIMER->ARR = 36000; // 18mS
INTMODULE_TIMER->CCR2 = 32000; // Update time
INTMODULE_TIMER->PSC = INTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
INTMODULE_TIMER->CCER = TIM_CCER_CC3E;
INTMODULE_TIMER->CCMR2 = 0;
INTMODULE_TIMER->EGR = 1; // Restart
INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0; // Toggle CC1 o/p
INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
INTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(INTMODULE_TIMER_IRQn);
NVIC_SetPriority(INTMODULE_TIMER_IRQn, 7);
}
void intmodulePxxStart()
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
INTERNAL_MODULE_ON();
NVIC_InitStructure.NVIC_IRQChannel = INTMODULE_DMA_STREAM_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// TX Pin
GPIO_PinAFConfig(INTMODULE_TX_GPIO, INTMODULE_TX_GPIO_PinSource, INTMODULE_GPIO_AF);
GPIO_InitStructure.GPIO_Pin = INTMODULE_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(INTMODULE_TX_GPIO, &GPIO_InitStructure);
// RX Pin
GPIO_PinAFConfig(INTMODULE_RX_GPIO, INTMODULE_RX_GPIO_PinSource, INTMODULE_GPIO_AF);
GPIO_InitStructure.GPIO_Pin = INTMODULE_RX_GPIO_PIN;
GPIO_Init(INTMODULE_RX_GPIO, &GPIO_InitStructure);
// UART config
USART_DeInit(INTMODULE_USART);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(INTMODULE_USART, &USART_InitStructure);
USART_Cmd(INTMODULE_USART, ENABLE);
// Timer
INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
INTMODULE_TIMER->ARR = 18000; // 9mS
INTMODULE_TIMER->CCR2 = 15000; // Update time
INTMODULE_TIMER->PSC = INTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
INTMODULE_TIMER->CCER = TIM_CCER_CC3E;
INTMODULE_TIMER->CCMR2 = 0;
INTMODULE_TIMER->EGR = 1; // Restart
INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0; // Toggle CC1 o/p
INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
INTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(INTMODULE_TIMER_IRQn);
NVIC_SetPriority(INTMODULE_TIMER_IRQn, 7);
}
extern "C" void INTMODULE_DMA_STREAM_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_DMA2S7);
if (DMA_GetITStatus(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC)) {
// TODO we could send the 8 next channels here (when needed)
DMA_ClearITPendingBit(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC);
}
}
void intmoduleSendNextFrame()
{
if (s_current_protocol[INTERNAL_MODULE] == PROTO_PXX) {
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(INTMODULE_DMA_STREAM);
DMA_InitStructure.DMA_Channel = INTMODULE_DMA_CHANNEL;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&INTMODULE_USART->DR);
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(modulePulsesData[INTERNAL_MODULE].pxx_uart.pulses);
DMA_InitStructure.DMA_BufferSize = modulePulsesData[INTERNAL_MODULE].pxx_uart.ptr - modulePulsesData[INTERNAL_MODULE].pxx_uart.pulses;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(INTMODULE_DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(INTMODULE_DMA_STREAM, ENABLE);
USART_DMACmd(INTMODULE_USART, USART_DMAReq_Tx, ENABLE);
}
}
extern "C" void INTMODULE_TIMER_IRQHandler()
{
DEBUG_INTERRUPT(INT_TIM1CC);
DEBUG_TIMER_SAMPLE(debugTimerIntPulses);
DEBUG_TIMER_START(debugTimerIntPulsesDuration);
INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // clear flag
setupPulses(INTERNAL_MODULE);
intmoduleSendNextFrame();
DEBUG_TIMER_STOP(debugTimerIntPulsesDuration);
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void intmoduleStop(void);
void extmoduleStop(void);
void intmoduleNoneStart(void);
void intmodulePxxStart(void);
void extmoduleNoneStart(void);
void extmodulePpmStart(void);
void extmodulePxxStart(void);
#if defined(DSM2)
void extmoduleDsm2Start(void);
#endif
void extmoduleCrossfireStart(void);
void init_no_pulses(uint32_t port)
{
if (port == INTERNAL_MODULE)
intmoduleNoneStart();
else
extmoduleNoneStart();
}
void disable_no_pulses(uint32_t port)
{
if (port == INTERNAL_MODULE)
intmoduleStop();
else
extmoduleStop();
}
void init_ppm(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmodulePpmStart();
}
}
void disable_ppm(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleStop();
}
}
void init_pxx(uint32_t port)
{
if (port == INTERNAL_MODULE)
intmodulePxxStart();
else
extmodulePxxStart();
}
void disable_pxx(uint32_t port)
{
if (port == INTERNAL_MODULE)
intmoduleStop();
else
extmoduleStop();
}
#if defined(DSM2)
void init_dsm2(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleDsm2Start();
}
}
void disable_dsm2(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleStop();
}
}
#endif
#if defined(MULTIMODULE)
void init_multimodule(uint32_t port)
{
init_dsm2(port);
}
void disable_multimodule(uint32_t port)
{
disable_dsm2(port);
}
#endif
void init_crossfire(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleCrossfireStart();
}
}
void disable_crossfire(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleStop();
}
}
void intmoduleStop()
{
INTERNAL_MODULE_OFF();
NVIC_DisableIRQ(INTMODULE_TIMER_IRQn);
INTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE;
INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
}
void intmoduleNoneStart()
{
INTERNAL_MODULE_OFF();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = INTMODULE_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(INTMODULE_TX_GPIO, &GPIO_InitStructure);
GPIO_SetBits(INTMODULE_TX_GPIO, INTMODULE_TX_GPIO_PIN); // Set high
INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
INTMODULE_TIMER->ARR = 36000; // 18mS
INTMODULE_TIMER->CCR2 = 32000; // Update time
INTMODULE_TIMER->PSC = INTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
INTMODULE_TIMER->CCER = TIM_CCER_CC3E;
INTMODULE_TIMER->CCMR2 = 0;
INTMODULE_TIMER->EGR = 1; // Restart
INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0; // Toggle CC1 o/p
INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
INTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(INTMODULE_TIMER_IRQn);
NVIC_SetPriority(INTMODULE_TIMER_IRQn, 7);
}
void intmodulePxxStart()
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
INTERNAL_MODULE_ON();
NVIC_InitStructure.NVIC_IRQChannel = INTMODULE_DMA_STREAM_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// TX Pin
GPIO_PinAFConfig(INTMODULE_TX_GPIO, INTMODULE_TX_GPIO_PinSource, INTMODULE_GPIO_AF);
GPIO_InitStructure.GPIO_Pin = INTMODULE_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(INTMODULE_TX_GPIO, &GPIO_InitStructure);
// RX Pin
GPIO_PinAFConfig(INTMODULE_RX_GPIO, INTMODULE_RX_GPIO_PinSource, INTMODULE_GPIO_AF);
GPIO_InitStructure.GPIO_Pin = INTMODULE_RX_GPIO_PIN;
GPIO_Init(INTMODULE_RX_GPIO, &GPIO_InitStructure);
// UART config
USART_DeInit(INTMODULE_USART);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(INTMODULE_USART, &USART_InitStructure);
USART_Cmd(INTMODULE_USART, ENABLE);
// Timer
INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN;
INTMODULE_TIMER->ARR = 18000; // 9mS
INTMODULE_TIMER->CCR2 = 15000; // Update time
INTMODULE_TIMER->PSC = INTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz)
INTMODULE_TIMER->CCER = TIM_CCER_CC3E;
INTMODULE_TIMER->CCMR2 = 0;
INTMODULE_TIMER->EGR = 1; // Restart
INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0; // Toggle CC1 o/p
INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag
INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt
INTMODULE_TIMER->CR1 |= TIM_CR1_CEN;
NVIC_EnableIRQ(INTMODULE_TIMER_IRQn);
NVIC_SetPriority(INTMODULE_TIMER_IRQn, 7);
}
extern "C" void INTMODULE_DMA_STREAM_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_DMA2S7);
if (DMA_GetITStatus(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC)) {
// TODO we could send the 8 next channels here (when needed)
DMA_ClearITPendingBit(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC);
}
}
void intmoduleSendNextFrame()
{
if (s_current_protocol[INTERNAL_MODULE] == PROTO_PXX) {
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(INTMODULE_DMA_STREAM);
DMA_InitStructure.DMA_Channel = INTMODULE_DMA_CHANNEL;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&INTMODULE_USART->DR);
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(modulePulsesData[INTERNAL_MODULE].pxx_uart.pulses);
DMA_InitStructure.DMA_BufferSize = modulePulsesData[INTERNAL_MODULE].pxx_uart.ptr - modulePulsesData[INTERNAL_MODULE].pxx_uart.pulses;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(INTMODULE_DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(INTMODULE_DMA_STREAM, ENABLE);
USART_DMACmd(INTMODULE_USART, USART_DMAReq_Tx, ENABLE);
}
}
extern "C" void INTMODULE_TIMER_IRQHandler()
{
DEBUG_INTERRUPT(INT_TIM1CC);
DEBUG_TIMER_SAMPLE(debugTimerIntPulses);
DEBUG_TIMER_START(debugTimerIntPulsesDuration);
INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // clear flag
setupPulses(INTERNAL_MODULE);
intmoduleSendNextFrame();
DEBUG_TIMER_STOP(debugTimerIntPulsesDuration);
}

View file

@ -1,150 +1,150 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "pwr.h"
#include "board.h"
uint32_t shutdownRequest; // Stores intentional shutdown to avoid reboot loop
uint32_t shutdownReason; // Used for detecting unexpected reboots regardless of reason
uint32_t powerupReason __NOINIT; // Stores power up reason beyond initialization for emergency mode activation
void pwrInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(PWR_GPIO, &GPIO_InitStructure);
// Init Module PWR
GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN);
GPIO_InitStructure.GPIO_Pin = INTMODULE_PWR_GPIO_PIN;
GPIO_Init(INTMODULE_PWR_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN);
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PWR_GPIO_PIN;
GPIO_Init(EXTMODULE_PWR_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
// Init PWR SWITCH PIN
GPIO_InitStructure.GPIO_Pin = PWR_SWITCH_GPIO_PIN;
GPIO_Init(PWR_GPIO, &GPIO_InitStructure);
// Init PCBREV PIN
// TODO to be removed on X10?
GPIO_ResetBits(PCBREV_GPIO, PCBREV_GPIO_PIN);
GPIO_InitStructure.GPIO_Pin = PCBREV_GPIO_PIN;
GPIO_Init(PCBREV_GPIO, &GPIO_InitStructure);
// Init SD-DETECT PIN
GPIO_ResetBits(SD_PRESENT_GPIO, SD_PRESENT_GPIO_PIN);
GPIO_InitStructure.GPIO_Pin = SD_PRESENT_GPIO_PIN;
GPIO_Init(SD_PRESENT_GPIO, &GPIO_InitStructure);
// Init TRAINER DETECT PIN
GPIO_InitStructure.GPIO_Pin = TRAINER_DETECT_GPIO_PIN;
GPIO_Init(TRAINER_DETECT_GPIO, &GPIO_InitStructure);
pwrOn();
}
void pwrOn()
{
GPIO_SetBits(PWR_GPIO, PWR_ON_GPIO_PIN);
shutdownRequest = NO_SHUTDOWN_REQUEST;
shutdownReason = DIRTY_SHUTDOWN;
}
void pwrOff()
{
#if defined(PCBX12S)
// Shutdown the Audio amp
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = AUDIO_SHUTDOWN_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(AUDIO_SHUTDOWN_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(AUDIO_SHUTDOWN_GPIO, AUDIO_SHUTDOWN_GPIO_PIN);
#endif
// Shutdown the Haptic
hapticDone();
shutdownRequest = SHUTDOWN_REQUEST;
shutdownReason = NORMAL_POWER_OFF;
GPIO_ResetBits(PWR_GPIO, PWR_ON_GPIO_PIN);
}
uint32_t pwrPressed()
{
return GPIO_ReadInputDataBit(PWR_GPIO, PWR_SWITCH_GPIO_PIN) == Bit_RESET;
}
void pwrResetHandler()
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOJEN;
// these two NOPs are needed (see STM32F errata sheet) before the peripheral
// register can be written after the peripheral clock was enabled
__ASM volatile ("nop");
__ASM volatile ("nop");
// We get here whether we are powering up normally, we had an unexpected reboot or we have just powered down normally.
// We want:
// - In the 2nd case, to power ON as soon as possible if an unexpected reboot happened
// (we get there running on remaining capacitor charge, soft power having been cut by the RESET).
// - In the 3rd case, NOT power on as that would prevent from turning the system off.
// - The 1st case does not need to be handled here, but will be as a result of the handling for the 3rd case, see below.
//
// shutdownRequest is used to handle the 3rd case. If we really powered down on purpose this will still be set to SHUTDOWN_REQUEST
// as we left it in pwrOff(). If however we had an unexpected reboot, it would be set to NO_SHUTDOWN_REQUEST as we set it in pwrOn().
// Any other value (e.g. resulting from data corruption) would also keep power on for safety, so this variable can NOT be used
// to detect an unexpected reboot (on a normal power on the contents of the variable are random).
//
// shutdownReason is used to differentiate between an unexpected reboot and a normal power on. We set it to DIRTY_SHUTDOWN in pwrOn()
// in anticipation of a potential reboot. Should there be one the value should be preserved and signal below that we rebooted unexpectedly.
// If it is NOT set to DIRTY_SHUTDOWN we likely had a normal boot and its contents are random. Due to the need to initialize it to detect a
// potential failure ASAP we cannot use it to determine in the firmware why we got there, it has to be buffered.
//
// powerupReason is there to cater for that, and is what is used in the firmware to decide whether we have to enter emergency mode.
// This variable needs to be in a RAM section that is not initialized or zeroed, since once we exit this pwrResetHandler() function the
// C runtime would otherwise overwrite it during program init.
if (shutdownRequest != SHUTDOWN_REQUEST) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(PWR_GPIO, &GPIO_InitStructure);
if (shutdownReason == DIRTY_SHUTDOWN) {
powerupReason = DIRTY_SHUTDOWN;
}
pwrOn();
}
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "pwr.h"
#include "board.h"
uint32_t shutdownRequest; // Stores intentional shutdown to avoid reboot loop
uint32_t shutdownReason; // Used for detecting unexpected reboots regardless of reason
uint32_t powerupReason __NOINIT; // Stores power up reason beyond initialization for emergency mode activation
void pwrInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(PWR_GPIO, &GPIO_InitStructure);
// Init Module PWR
GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN);
GPIO_InitStructure.GPIO_Pin = INTMODULE_PWR_GPIO_PIN;
GPIO_Init(INTMODULE_PWR_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN);
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PWR_GPIO_PIN;
GPIO_Init(EXTMODULE_PWR_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
// Init PWR SWITCH PIN
GPIO_InitStructure.GPIO_Pin = PWR_SWITCH_GPIO_PIN;
GPIO_Init(PWR_GPIO, &GPIO_InitStructure);
// Init PCBREV PIN
// TODO to be removed on X10?
GPIO_ResetBits(PCBREV_GPIO, PCBREV_GPIO_PIN);
GPIO_InitStructure.GPIO_Pin = PCBREV_GPIO_PIN;
GPIO_Init(PCBREV_GPIO, &GPIO_InitStructure);
// Init SD-DETECT PIN
GPIO_ResetBits(SD_PRESENT_GPIO, SD_PRESENT_GPIO_PIN);
GPIO_InitStructure.GPIO_Pin = SD_PRESENT_GPIO_PIN;
GPIO_Init(SD_PRESENT_GPIO, &GPIO_InitStructure);
// Init TRAINER DETECT PIN
GPIO_InitStructure.GPIO_Pin = TRAINER_DETECT_GPIO_PIN;
GPIO_Init(TRAINER_DETECT_GPIO, &GPIO_InitStructure);
pwrOn();
}
void pwrOn()
{
GPIO_SetBits(PWR_GPIO, PWR_ON_GPIO_PIN);
shutdownRequest = NO_SHUTDOWN_REQUEST;
shutdownReason = DIRTY_SHUTDOWN;
}
void pwrOff()
{
#if defined(PCBX12S)
// Shutdown the Audio amp
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = AUDIO_SHUTDOWN_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(AUDIO_SHUTDOWN_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(AUDIO_SHUTDOWN_GPIO, AUDIO_SHUTDOWN_GPIO_PIN);
#endif
// Shutdown the Haptic
hapticDone();
shutdownRequest = SHUTDOWN_REQUEST;
shutdownReason = NORMAL_POWER_OFF;
GPIO_ResetBits(PWR_GPIO, PWR_ON_GPIO_PIN);
}
uint32_t pwrPressed()
{
return GPIO_ReadInputDataBit(PWR_GPIO, PWR_SWITCH_GPIO_PIN) == Bit_RESET;
}
void pwrResetHandler()
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOJEN;
// these two NOPs are needed (see STM32F errata sheet) before the peripheral
// register can be written after the peripheral clock was enabled
__ASM volatile ("nop");
__ASM volatile ("nop");
// We get here whether we are powering up normally, we had an unexpected reboot or we have just powered down normally.
// We want:
// - In the 2nd case, to power ON as soon as possible if an unexpected reboot happened
// (we get there running on remaining capacitor charge, soft power having been cut by the RESET).
// - In the 3rd case, NOT power on as that would prevent from turning the system off.
// - The 1st case does not need to be handled here, but will be as a result of the handling for the 3rd case, see below.
//
// shutdownRequest is used to handle the 3rd case. If we really powered down on purpose this will still be set to SHUTDOWN_REQUEST
// as we left it in pwrOff(). If however we had an unexpected reboot, it would be set to NO_SHUTDOWN_REQUEST as we set it in pwrOn().
// Any other value (e.g. resulting from data corruption) would also keep power on for safety, so this variable can NOT be used
// to detect an unexpected reboot (on a normal power on the contents of the variable are random).
//
// shutdownReason is used to differentiate between an unexpected reboot and a normal power on. We set it to DIRTY_SHUTDOWN in pwrOn()
// in anticipation of a potential reboot. Should there be one the value should be preserved and signal below that we rebooted unexpectedly.
// If it is NOT set to DIRTY_SHUTDOWN we likely had a normal boot and its contents are random. Due to the need to initialize it to detect a
// potential failure ASAP we cannot use it to determine in the firmware why we got there, it has to be buffered.
//
// powerupReason is there to cater for that, and is what is used in the firmware to decide whether we have to enter emergency mode.
// This variable needs to be in a RAM section that is not initialized or zeroed, since once we exit this pwrResetHandler() function the
// C runtime would otherwise overwrite it during program init.
if (shutdownRequest != SHUTDOWN_REQUEST) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(PWR_GPIO, &GPIO_InitStructure);
if (shutdownReason == DIRTY_SHUTDOWN) {
powerupReason = DIRTY_SHUTDOWN;
}
pwrOn();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,220 +1,220 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _SDIO_SD_H_
#define _SDIO_SD_H_
#include "board.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
typedef enum
{
/**
* @brief SDIO specific error defines
*/
SD_CMD_CRC_FAIL = (1), /*!< Command response received (but CRC check failed) */
SD_DATA_CRC_FAIL = (2), /*!< Data bock sent/received (CRC check Failed) */
SD_CMD_RSP_TIMEOUT = (3), /*!< Command response timeout */
SD_DATA_TIMEOUT = (4), /*!< Data time out */
SD_TX_UNDERRUN = (5), /*!< Transmit FIFO under-run */
SD_RX_OVERRUN = (6), /*!< Receive FIFO over-run */
SD_START_BIT_ERR = (7), /*!< Start bit not detected on all data signals in widE bus mode */
SD_CMD_OUT_OF_RANGE = (8), /*!< CMD's argument was out of range.*/
SD_ADDR_MISALIGNED = (9), /*!< Misaligned address */
SD_BLOCK_LEN_ERR = (10), /*!< Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */
SD_ERASE_SEQ_ERR = (11), /*!< An error in the sequence of erase command occurs.*/
SD_BAD_ERASE_PARAM = (12), /*!< An Invalid selection for erase groups */
SD_WRITE_PROT_VIOLATION = (13), /*!< Attempt to program a write protect block */
SD_LOCK_UNLOCK_FAILED = (14), /*!< Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */
SD_COM_CRC_FAILED = (15), /*!< CRC check of the previous command failed */
SD_ILLEGAL_CMD = (16), /*!< Command is not legal for the card state */
SD_CARD_ECC_FAILED = (17), /*!< Card internal ECC was applied but failed to correct the data */
SD_CC_ERROR = (18), /*!< Internal card controller error */
SD_GENERAL_UNKNOWN_ERROR = (19), /*!< General or Unknown error */
SD_STREAM_READ_UNDERRUN = (20), /*!< The card could not sustain data transfer in stream read operation. */
SD_STREAM_WRITE_OVERRUN = (21), /*!< The card could not sustain data programming in stream mode */
SD_CID_CSD_OVERWRITE = (22), /*!< CID/CSD overwrite error */
SD_WP_ERASE_SKIP = (23), /*!< only partial address space was erased */
SD_CARD_ECC_DISABLED = (24), /*!< Command has been executed without using internal ECC */
SD_ERASE_RESET = (25), /*!< Erase sequence was cleared before executing because an out of erase sequence command was received */
SD_AKE_SEQ_ERROR = (26), /*!< Error in sequence of authentication. */
SD_INVALID_VOLTRANGE = (27),
SD_ADDR_OUT_OF_RANGE = (28),
SD_SWITCH_ERROR = (29),
SD_SDIO_DISABLED = (30),
SD_SDIO_FUNCTION_BUSY = (31),
SD_SDIO_FUNCTION_FAILED = (32),
SD_SDIO_UNKNOWN_FUNCTION = (33),
/**
* @brief Standard error defines
*/
SD_INTERNAL_ERROR,
SD_NOT_CONFIGURED,
SD_REQUEST_PENDING,
SD_REQUEST_NOT_APPLICABLE,
SD_INVALID_PARAMETER,
SD_UNSUPPORTED_FEATURE,
SD_UNSUPPORTED_HW,
SD_ERROR,
SD_OK = 0
} SD_Error;
/**
* @brief SDIO Transfer state
*/
typedef enum
{
SD_TRANSFER_OK = 0,
SD_TRANSFER_BUSY = 1,
SD_TRANSFER_ERROR
} SDTransferState;
/**
* @brief Card Specific Data: CSD Register
*/
typedef struct
{
__IO uint8_t CSDStruct; /*!< CSD structure */
__IO uint8_t SysSpecVersion; /*!< System specification version */
__IO uint8_t Reserved1; /*!< Reserved */
__IO uint8_t TAAC; /*!< Data read access-time 1 */
__IO uint8_t NSAC; /*!< Data read access-time 2 in CLK cycles */
__IO uint8_t MaxBusClkFrec; /*!< Max. bus clock frequency */
__IO uint16_t CardComdClasses; /*!< Card command classes */
__IO uint8_t RdBlockLen; /*!< Max. read data block length */
__IO uint8_t PartBlockRead; /*!< Partial blocks for read allowed */
__IO uint8_t WrBlockMisalign; /*!< Write block misalignment */
__IO uint8_t RdBlockMisalign; /*!< Read block misalignment */
__IO uint8_t DSRImpl; /*!< DSR implemented */
__IO uint8_t Reserved2; /*!< Reserved */
__IO uint32_t DeviceSize; /*!< Device Size */
__IO uint8_t MaxRdCurrentVDDMin; /*!< Max. read current @ VDD min */
__IO uint8_t MaxRdCurrentVDDMax; /*!< Max. read current @ VDD max */
__IO uint8_t MaxWrCurrentVDDMin; /*!< Max. write current @ VDD min */
__IO uint8_t MaxWrCurrentVDDMax; /*!< Max. write current @ VDD max */
__IO uint8_t DeviceSizeMul; /*!< Device size multiplier */
__IO uint8_t EraseGrSize; /*!< Erase group size */
__IO uint8_t EraseGrMul; /*!< Erase group size multiplier */
__IO uint8_t WrProtectGrSize; /*!< Write protect group size */
__IO uint8_t WrProtectGrEnable; /*!< Write protect group enable */
__IO uint8_t ManDeflECC; /*!< Manufacturer default ECC */
__IO uint8_t WrSpeedFact; /*!< Write speed factor */
__IO uint8_t MaxWrBlockLen; /*!< Max. write data block length */
__IO uint8_t WriteBlockPaPartial; /*!< Partial blocks for write allowed */
__IO uint8_t Reserved3; /*!< Reserded */
__IO uint8_t ContentProtectAppli; /*!< Content protection application */
__IO uint8_t FileFormatGrouop; /*!< File format group */
__IO uint8_t CopyFlag; /*!< Copy flag (OTP) */
__IO uint8_t PermWrProtect; /*!< Permanent write protection */
__IO uint8_t TempWrProtect; /*!< Temporary write protection */
__IO uint8_t FileFormat; /*!< File Format */
__IO uint8_t ECC; /*!< ECC code */
__IO uint8_t CSD_CRC; /*!< CSD CRC */
__IO uint8_t Reserved4; /*!< always 1*/
} SD_CSD;
/**
* @brief Card Identification Data: CID Register
*/
typedef struct
{
__IO uint8_t ManufacturerID; /*!< ManufacturerID */
__IO uint16_t OEM_AppliID; /*!< OEM/Application ID */
__IO uint32_t ProdName1; /*!< Product Name part1 */
__IO uint8_t ProdName2; /*!< Product Name part2*/
__IO uint8_t ProdRev; /*!< Product Revision */
__IO uint32_t ProdSN; /*!< Product Serial Number */
__IO uint8_t Reserved1; /*!< Reserved1 */
__IO uint16_t ManufactDate; /*!< Manufacturing Date */
__IO uint8_t CID_CRC; /*!< CID CRC */
__IO uint8_t Reserved2; /*!< always 1 */
} SD_CID;
/**
* @brief SD Card Status
*/
// typedef struct
// {
// __IO uint8_t DAT_BUS_WIDTH;
// __IO uint8_t SECURED_MODE;
// __IO uint16_t SD_CARD_TYPE;
// __IO uint32_t SIZE_OF_PROTECTED_AREA;
// __IO uint8_t SPEED_CLASS;
// __IO uint8_t PERFORMANCE_MOVE;
// __IO uint8_t AU_SIZE;
// __IO uint16_t ERASE_SIZE;
// __IO uint8_t ERASE_TIMEOUT;
// __IO uint8_t ERASE_OFFSET;
// } SD_CardStatus;
/**
* @brief SD Card information
*/
typedef struct
{
SD_CSD SD_csd;
SD_CID SD_cid;
uint64_t CardCapacity; /*!< Card Capacity */
uint32_t CardBlockSize; /*!< Card Block Size */
uint16_t RCA;
uint8_t CardType;
} SD_CardInfo;
/**
* @brief SD detection on its memory slot
*/
#define SD_PRESENT ((uint8_t)0x01)
#define SD_NOT_PRESENT ((uint8_t)0x00)
// void SD_DeInit(void);
SD_Error SD_Init(void);
SDTransferState SD_GetStatus(void);
uint8_t SD_Detect(void);
SD_Error SD_PowerOFF(void);
// SD_Error SD_GetCardStatus(SD_CardStatus *cardstatus);
SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize);
SD_Error SD_ReadMultiBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);
// SD_Error SD_ReadMultiBlocksFIXED(uint8_t *readbuff, uint32_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize);
SD_Error SD_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);
// SD_Error SD_WriteMultiBlocksFIXED(uint8_t *writebuff, uint32_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
SDTransferState SD_GetTransferState(void);
// SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr);
// SD_Error SD_SendSDStatus(uint32_t *psdstatus);
SD_Error SD_WaitReadOperation(uint32_t timeout);
SD_Error SD_WaitWriteOperation(uint32_t timeout);
#ifdef __cplusplus
}
#endif
extern SD_CardInfo SDCardInfo;
#endif // _SDIO_SD_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _SDIO_SD_H_
#define _SDIO_SD_H_
#include "board.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
typedef enum
{
/**
* @brief SDIO specific error defines
*/
SD_CMD_CRC_FAIL = (1), /*!< Command response received (but CRC check failed) */
SD_DATA_CRC_FAIL = (2), /*!< Data bock sent/received (CRC check Failed) */
SD_CMD_RSP_TIMEOUT = (3), /*!< Command response timeout */
SD_DATA_TIMEOUT = (4), /*!< Data time out */
SD_TX_UNDERRUN = (5), /*!< Transmit FIFO under-run */
SD_RX_OVERRUN = (6), /*!< Receive FIFO over-run */
SD_START_BIT_ERR = (7), /*!< Start bit not detected on all data signals in widE bus mode */
SD_CMD_OUT_OF_RANGE = (8), /*!< CMD's argument was out of range.*/
SD_ADDR_MISALIGNED = (9), /*!< Misaligned address */
SD_BLOCK_LEN_ERR = (10), /*!< Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */
SD_ERASE_SEQ_ERR = (11), /*!< An error in the sequence of erase command occurs.*/
SD_BAD_ERASE_PARAM = (12), /*!< An Invalid selection for erase groups */
SD_WRITE_PROT_VIOLATION = (13), /*!< Attempt to program a write protect block */
SD_LOCK_UNLOCK_FAILED = (14), /*!< Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */
SD_COM_CRC_FAILED = (15), /*!< CRC check of the previous command failed */
SD_ILLEGAL_CMD = (16), /*!< Command is not legal for the card state */
SD_CARD_ECC_FAILED = (17), /*!< Card internal ECC was applied but failed to correct the data */
SD_CC_ERROR = (18), /*!< Internal card controller error */
SD_GENERAL_UNKNOWN_ERROR = (19), /*!< General or Unknown error */
SD_STREAM_READ_UNDERRUN = (20), /*!< The card could not sustain data transfer in stream read operation. */
SD_STREAM_WRITE_OVERRUN = (21), /*!< The card could not sustain data programming in stream mode */
SD_CID_CSD_OVERWRITE = (22), /*!< CID/CSD overwrite error */
SD_WP_ERASE_SKIP = (23), /*!< only partial address space was erased */
SD_CARD_ECC_DISABLED = (24), /*!< Command has been executed without using internal ECC */
SD_ERASE_RESET = (25), /*!< Erase sequence was cleared before executing because an out of erase sequence command was received */
SD_AKE_SEQ_ERROR = (26), /*!< Error in sequence of authentication. */
SD_INVALID_VOLTRANGE = (27),
SD_ADDR_OUT_OF_RANGE = (28),
SD_SWITCH_ERROR = (29),
SD_SDIO_DISABLED = (30),
SD_SDIO_FUNCTION_BUSY = (31),
SD_SDIO_FUNCTION_FAILED = (32),
SD_SDIO_UNKNOWN_FUNCTION = (33),
/**
* @brief Standard error defines
*/
SD_INTERNAL_ERROR,
SD_NOT_CONFIGURED,
SD_REQUEST_PENDING,
SD_REQUEST_NOT_APPLICABLE,
SD_INVALID_PARAMETER,
SD_UNSUPPORTED_FEATURE,
SD_UNSUPPORTED_HW,
SD_ERROR,
SD_OK = 0
} SD_Error;
/**
* @brief SDIO Transfer state
*/
typedef enum
{
SD_TRANSFER_OK = 0,
SD_TRANSFER_BUSY = 1,
SD_TRANSFER_ERROR
} SDTransferState;
/**
* @brief Card Specific Data: CSD Register
*/
typedef struct
{
__IO uint8_t CSDStruct; /*!< CSD structure */
__IO uint8_t SysSpecVersion; /*!< System specification version */
__IO uint8_t Reserved1; /*!< Reserved */
__IO uint8_t TAAC; /*!< Data read access-time 1 */
__IO uint8_t NSAC; /*!< Data read access-time 2 in CLK cycles */
__IO uint8_t MaxBusClkFrec; /*!< Max. bus clock frequency */
__IO uint16_t CardComdClasses; /*!< Card command classes */
__IO uint8_t RdBlockLen; /*!< Max. read data block length */
__IO uint8_t PartBlockRead; /*!< Partial blocks for read allowed */
__IO uint8_t WrBlockMisalign; /*!< Write block misalignment */
__IO uint8_t RdBlockMisalign; /*!< Read block misalignment */
__IO uint8_t DSRImpl; /*!< DSR implemented */
__IO uint8_t Reserved2; /*!< Reserved */
__IO uint32_t DeviceSize; /*!< Device Size */
__IO uint8_t MaxRdCurrentVDDMin; /*!< Max. read current @ VDD min */
__IO uint8_t MaxRdCurrentVDDMax; /*!< Max. read current @ VDD max */
__IO uint8_t MaxWrCurrentVDDMin; /*!< Max. write current @ VDD min */
__IO uint8_t MaxWrCurrentVDDMax; /*!< Max. write current @ VDD max */
__IO uint8_t DeviceSizeMul; /*!< Device size multiplier */
__IO uint8_t EraseGrSize; /*!< Erase group size */
__IO uint8_t EraseGrMul; /*!< Erase group size multiplier */
__IO uint8_t WrProtectGrSize; /*!< Write protect group size */
__IO uint8_t WrProtectGrEnable; /*!< Write protect group enable */
__IO uint8_t ManDeflECC; /*!< Manufacturer default ECC */
__IO uint8_t WrSpeedFact; /*!< Write speed factor */
__IO uint8_t MaxWrBlockLen; /*!< Max. write data block length */
__IO uint8_t WriteBlockPaPartial; /*!< Partial blocks for write allowed */
__IO uint8_t Reserved3; /*!< Reserded */
__IO uint8_t ContentProtectAppli; /*!< Content protection application */
__IO uint8_t FileFormatGrouop; /*!< File format group */
__IO uint8_t CopyFlag; /*!< Copy flag (OTP) */
__IO uint8_t PermWrProtect; /*!< Permanent write protection */
__IO uint8_t TempWrProtect; /*!< Temporary write protection */
__IO uint8_t FileFormat; /*!< File Format */
__IO uint8_t ECC; /*!< ECC code */
__IO uint8_t CSD_CRC; /*!< CSD CRC */
__IO uint8_t Reserved4; /*!< always 1*/
} SD_CSD;
/**
* @brief Card Identification Data: CID Register
*/
typedef struct
{
__IO uint8_t ManufacturerID; /*!< ManufacturerID */
__IO uint16_t OEM_AppliID; /*!< OEM/Application ID */
__IO uint32_t ProdName1; /*!< Product Name part1 */
__IO uint8_t ProdName2; /*!< Product Name part2*/
__IO uint8_t ProdRev; /*!< Product Revision */
__IO uint32_t ProdSN; /*!< Product Serial Number */
__IO uint8_t Reserved1; /*!< Reserved1 */
__IO uint16_t ManufactDate; /*!< Manufacturing Date */
__IO uint8_t CID_CRC; /*!< CID CRC */
__IO uint8_t Reserved2; /*!< always 1 */
} SD_CID;
/**
* @brief SD Card Status
*/
// typedef struct
// {
// __IO uint8_t DAT_BUS_WIDTH;
// __IO uint8_t SECURED_MODE;
// __IO uint16_t SD_CARD_TYPE;
// __IO uint32_t SIZE_OF_PROTECTED_AREA;
// __IO uint8_t SPEED_CLASS;
// __IO uint8_t PERFORMANCE_MOVE;
// __IO uint8_t AU_SIZE;
// __IO uint16_t ERASE_SIZE;
// __IO uint8_t ERASE_TIMEOUT;
// __IO uint8_t ERASE_OFFSET;
// } SD_CardStatus;
/**
* @brief SD Card information
*/
typedef struct
{
SD_CSD SD_csd;
SD_CID SD_cid;
uint64_t CardCapacity; /*!< Card Capacity */
uint32_t CardBlockSize; /*!< Card Block Size */
uint16_t RCA;
uint8_t CardType;
} SD_CardInfo;
/**
* @brief SD detection on its memory slot
*/
#define SD_PRESENT ((uint8_t)0x01)
#define SD_NOT_PRESENT ((uint8_t)0x00)
// void SD_DeInit(void);
SD_Error SD_Init(void);
SDTransferState SD_GetStatus(void);
uint8_t SD_Detect(void);
SD_Error SD_PowerOFF(void);
// SD_Error SD_GetCardStatus(SD_CardStatus *cardstatus);
SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize);
SD_Error SD_ReadMultiBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);
// SD_Error SD_ReadMultiBlocksFIXED(uint8_t *readbuff, uint32_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize);
SD_Error SD_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);
// SD_Error SD_WriteMultiBlocksFIXED(uint8_t *writebuff, uint32_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
SDTransferState SD_GetTransferState(void);
// SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr);
// SD_Error SD_SendSDStatus(uint32_t *psdstatus);
SD_Error SD_WaitReadOperation(uint32_t timeout);
SD_Error SD_WaitWriteOperation(uint32_t timeout);
#ifdef __cplusplus
}
#endif
extern SD_CardInfo SDCardInfo;
#endif // _SDIO_SD_H_

View file

@ -1,466 +1,466 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "board.h"
#define SDRAM_MEMORY_WIDTH FMC_SDMemory_Width_16b
#define SDRAM_CAS_LATENCY FMC_CAS_Latency_3
#define SDCLOCK_PERIOD FMC_SDClock_Period_2
#define SDRAM_TIMEOUT ((uint32_t)0xFFFF)
/**
* @brief FMC SDRAM Mode definition register defines
*/
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
/**
* @brief FMC SDRAM Memory Read Burst feature
*/
#define SDRAM_READBURST FMC_Read_Burst_Disable
static void __Delay(__IO uint32_t nCount)
{
__IO uint32_t index = 0;
for(index = (100000 * nCount); index != 0; index--)
{
}
}
/**
* @brief Configures all SDRAM memory I/Os pins.
* @param None.
* @retval None.
*/
void SDRAM_GPIOConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOs clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD |
RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG|RCC_AHB1Periph_GPIOH, ENABLE);
/*-- GPIOs Configuration -----------------------------------------------------*/
/*
+-------------------+--------------------+--------------------+--------------------+
+ SDRAM pins assignment +
+-------------------+--------------------+--------------------+--------------------+
| PD0 <-> FMC_D2 | PE0 <-> FMC_NBL0 | PF0 <-> FMC_A0 | PG0 <-> FMC_A10 |
| PD1 <-> FMC_D3 | PE1 <-> FMC_NBL1 | PF1 <-> FMC_A1 | PG1 <-> FMC_A11 |
| PD8 <-> FMC_D13 | PE7 <-> FMC_D4 | PF2 <-> FMC_A2 | PG8 <-> FMC_SDCLK |
| PD9 <-> FMC_D14 | PE8 <-> FMC_D5 | PF3 <-> FMC_A3 | PG15 <-> FMC_NCAS |
| PD10 <-> FMC_D15 | PE9 <-> FMC_D6 | PF4 <-> FMC_A4 |--------------------+
| PD14 <-> FMC_D0 | PE10 <-> FMC_D7 | PF5 <-> FMC_A5 |
| PD15 <-> FMC_D1 | PE11 <-> FMC_D8 | PF11 <-> FMC_NRAS |
+-------------------| PE12 <-> FMC_D9 | PF12 <-> FMC_A6 |
| PE13 <-> FMC_D10 | PF13 <-> FMC_A7 |
| PE14 <-> FMC_D11 | PF14 <-> FMC_A8 |
| PE15 <-> FMC_D12 | PF15 <-> FMC_A9 |
+-------------------+--------------------+--------------------+
| PB5 <-> FMC_SDCKE1|
| PB6 <-> FMC_SDNE1 |
| PH5 <-> FMC_SDNWE |///////
+-------------------+
*/
/* Common GPIO configuration */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
/* GPIOB configuration */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource5 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* GPIOC configuration */
GPIO_PinAFConfig(GPIOH, GPIO_PinSource5 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOH, GPIO_PinSource6 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
GPIO_Init(GPIOH, &GPIO_InitStructure);
/* GPIOD configuration */
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 |
GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 |
GPIO_Pin_15;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* GPIOE configuration */
GPIO_PinAFConfig(GPIOE, GPIO_PinSource0 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource1 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource7 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource8 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource9 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource10 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource11 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource12 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource13 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource14 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource15 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_7 |
GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |
GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 |
GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/* GPIOF configuration */
GPIO_PinAFConfig(GPIOF, GPIO_PinSource0 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource1 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource2 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource3 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource4 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource5 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource11 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource12 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource13 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource14 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource15 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |
GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 |
GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOF, &GPIO_InitStructure);
/* GPIOG configuration */
GPIO_PinAFConfig(GPIOG, GPIO_PinSource0 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource1 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource4 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource5 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource8 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource15 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 |
GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_15;
GPIO_Init(GPIOG, &GPIO_InitStructure);
}
/**
* @brief Executes the SDRAM memory initialization sequence.
* @param None.
* @retval None.
*/
void SDRAM_InitSequence(void)
{
FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure;
uint32_t tmpr = 0;
uint32_t timeout = SDRAM_TIMEOUT;
/* Step 3 --------------------------------------------------------------------*/
/* Configure a clock configuration enable command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 4 --------------------------------------------------------------------*/
/* Insert 100 ms delay */
__Delay(10);
/* Step 5 --------------------------------------------------------------------*/
/* Configure a PALL (precharge all) command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 6 --------------------------------------------------------------------*/
/* Configure a Auto-Refresh command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 8;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 7 --------------------------------------------------------------------*/
/* Program the external memory mode register */
tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
/* Configure a load Mode register command*/
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_LoadMode;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr;
/* Wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 8 --------------------------------------------------------------------*/
/* Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
/* Set the device refresh counter */
FMC_SetRefreshCount(1385);
/* Wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
}
/**
* @brief Executes the SDRAM memory initialization sequence.
* @param None.
* @retval None.
*/
void SDRAMTest_InitSequence(void)
{
FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure;
uint32_t tmpr = 0;
/* Step 3 --------------------------------------------------------------------*/
/* Configure a clock configuration enable command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 4 --------------------------------------------------------------------*/
/* Insert 100 ms delay */
__Delay(10);
/* Step 5 --------------------------------------------------------------------*/
/* Configure a PALL (precharge all) command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 6 --------------------------------------------------------------------*/
/* Configure a Auto-Refresh command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 4;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the first command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the second command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 7 --------------------------------------------------------------------*/
/* Program the external memory mode register */
tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
/* Configure a load Mode register command*/
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_LoadMode;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr;
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 8 --------------------------------------------------------------------*/
/* Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
/* Set the device refresh counter */
FMC_SetRefreshCount(1386);
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
}
void SDRAM_Init(void)
{
FMC_SDRAMInitTypeDef FMC_SDRAMInitStructure;
FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingInitStructure;
/* GPIO configuration for FMC SDRAM bank */
SDRAM_GPIOConfig();
/* Enable FMC clock */
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);
/* FMC Configuration ---------------------------------------------------------*/
/* FMC SDRAM Bank configuration */
/* Timing configuration for 90 Mhz of SD clock frequency (168Mhz/2) */
/* TMRD: 2 Clock cycles */
FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2;
/* TXSR: min=70ns (7x11.11ns) */
FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7;
/* TRAS: min=42ns (4x11.11ns) max=120k (ns) */
FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4;
/* TRC: min=70 (7x11.11ns) */
FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 7;
/* TWR: min=1+ 7ns (1+1x11.11ns) */
FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 2;
/* TRP: 20ns => 2x11.11ns */
FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2;
/* TRCD: 20ns => 2x11.11ns */
FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2;
/* FMC SDRAM control configuration */
FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank2_SDRAM;
/* Row addressing: [7:0] */
FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;
/* Column addressing: [11:0] */
FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_12b;
FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = SDRAM_MEMORY_WIDTH;
FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
FMC_SDRAMInitStructure.FMC_CASLatency = SDRAM_CAS_LATENCY;
FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable;
FMC_SDRAMInitStructure.FMC_SDClockPeriod = SDCLOCK_PERIOD;
FMC_SDRAMInitStructure.FMC_ReadBurst = SDRAM_READBURST;
FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_0;
FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingInitStructure;
/* FMC SDRAM bank initialization */
FMC_SDRAMInit(&FMC_SDRAMInitStructure);
/* FMC SDRAM device initialization sequence */
SDRAMTest_InitSequence();
}
#if 0
void SDRAM_WriteBuffer(uint32_t* pBuffer, uint32_t uwWriteAddress, uint32_t uwBufferSize)
{
__IO uint32_t write_pointer = (uint32_t)uwWriteAddress;
FMC_SDRAMWriteProtectionConfig(FMC_Bank1_SDRAM, DISABLE);
while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
for (; uwBufferSize != 0; uwBufferSize--)
{
*(uint32_t *) (SDRAM_BANK_ADDR + write_pointer) = *pBuffer++;
write_pointer += 4;
}
}
void SDRAM_ReadBuffer(uint32_t* pBuffer, uint32_t uwReadAddress, uint32_t uwBufferSize)
{
__IO uint32_t write_pointer = (uint32_t)uwReadAddress;
while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
for(; uwBufferSize != 0x00; uwBufferSize--)
{
*pBuffer++ = *(__IO uint32_t *)(SDRAM_BANK_ADDR + write_pointer );
write_pointer += 4;
}
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "board.h"
#define SDRAM_MEMORY_WIDTH FMC_SDMemory_Width_16b
#define SDRAM_CAS_LATENCY FMC_CAS_Latency_3
#define SDCLOCK_PERIOD FMC_SDClock_Period_2
#define SDRAM_TIMEOUT ((uint32_t)0xFFFF)
/**
* @brief FMC SDRAM Mode definition register defines
*/
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
/**
* @brief FMC SDRAM Memory Read Burst feature
*/
#define SDRAM_READBURST FMC_Read_Burst_Disable
static void __Delay(__IO uint32_t nCount)
{
__IO uint32_t index = 0;
for(index = (100000 * nCount); index != 0; index--)
{
}
}
/**
* @brief Configures all SDRAM memory I/Os pins.
* @param None.
* @retval None.
*/
void SDRAM_GPIOConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOs clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD |
RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG|RCC_AHB1Periph_GPIOH, ENABLE);
/*-- GPIOs Configuration -----------------------------------------------------*/
/*
+-------------------+--------------------+--------------------+--------------------+
+ SDRAM pins assignment +
+-------------------+--------------------+--------------------+--------------------+
| PD0 <-> FMC_D2 | PE0 <-> FMC_NBL0 | PF0 <-> FMC_A0 | PG0 <-> FMC_A10 |
| PD1 <-> FMC_D3 | PE1 <-> FMC_NBL1 | PF1 <-> FMC_A1 | PG1 <-> FMC_A11 |
| PD8 <-> FMC_D13 | PE7 <-> FMC_D4 | PF2 <-> FMC_A2 | PG8 <-> FMC_SDCLK |
| PD9 <-> FMC_D14 | PE8 <-> FMC_D5 | PF3 <-> FMC_A3 | PG15 <-> FMC_NCAS |
| PD10 <-> FMC_D15 | PE9 <-> FMC_D6 | PF4 <-> FMC_A4 |--------------------+
| PD14 <-> FMC_D0 | PE10 <-> FMC_D7 | PF5 <-> FMC_A5 |
| PD15 <-> FMC_D1 | PE11 <-> FMC_D8 | PF11 <-> FMC_NRAS |
+-------------------| PE12 <-> FMC_D9 | PF12 <-> FMC_A6 |
| PE13 <-> FMC_D10 | PF13 <-> FMC_A7 |
| PE14 <-> FMC_D11 | PF14 <-> FMC_A8 |
| PE15 <-> FMC_D12 | PF15 <-> FMC_A9 |
+-------------------+--------------------+--------------------+
| PB5 <-> FMC_SDCKE1|
| PB6 <-> FMC_SDNE1 |
| PH5 <-> FMC_SDNWE |///////
+-------------------+
*/
/* Common GPIO configuration */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
/* GPIOB configuration */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource5 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* GPIOC configuration */
GPIO_PinAFConfig(GPIOH, GPIO_PinSource5 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOH, GPIO_PinSource6 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
GPIO_Init(GPIOH, &GPIO_InitStructure);
/* GPIOD configuration */
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 |
GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 |
GPIO_Pin_15;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* GPIOE configuration */
GPIO_PinAFConfig(GPIOE, GPIO_PinSource0 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource1 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource7 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource8 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource9 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource10 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource11 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource12 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource13 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource14 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource15 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_7 |
GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |
GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 |
GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/* GPIOF configuration */
GPIO_PinAFConfig(GPIOF, GPIO_PinSource0 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource1 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource2 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource3 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource4 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource5 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource11 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource12 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource13 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource14 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource15 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |
GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 |
GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOF, &GPIO_InitStructure);
/* GPIOG configuration */
GPIO_PinAFConfig(GPIOG, GPIO_PinSource0 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource1 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource4 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource5 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource8 , GPIO_AF_FMC);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource15 , GPIO_AF_FMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 |
GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_15;
GPIO_Init(GPIOG, &GPIO_InitStructure);
}
/**
* @brief Executes the SDRAM memory initialization sequence.
* @param None.
* @retval None.
*/
void SDRAM_InitSequence(void)
{
FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure;
uint32_t tmpr = 0;
uint32_t timeout = SDRAM_TIMEOUT;
/* Step 3 --------------------------------------------------------------------*/
/* Configure a clock configuration enable command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 4 --------------------------------------------------------------------*/
/* Insert 100 ms delay */
__Delay(10);
/* Step 5 --------------------------------------------------------------------*/
/* Configure a PALL (precharge all) command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 6 --------------------------------------------------------------------*/
/* Configure a Auto-Refresh command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 8;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 7 --------------------------------------------------------------------*/
/* Program the external memory mode register */
tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
/* Configure a load Mode register command*/
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_LoadMode;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr;
/* Wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 8 --------------------------------------------------------------------*/
/* Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
/* Set the device refresh counter */
FMC_SetRefreshCount(1385);
/* Wait until the SDRAM controller is ready */
timeout = SDRAM_TIMEOUT;
while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
{
timeout--;
}
}
/**
* @brief Executes the SDRAM memory initialization sequence.
* @param None.
* @retval None.
*/
void SDRAMTest_InitSequence(void)
{
FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure;
uint32_t tmpr = 0;
/* Step 3 --------------------------------------------------------------------*/
/* Configure a clock configuration enable command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 4 --------------------------------------------------------------------*/
/* Insert 100 ms delay */
__Delay(10);
/* Step 5 --------------------------------------------------------------------*/
/* Configure a PALL (precharge all) command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 6 --------------------------------------------------------------------*/
/* Configure a Auto-Refresh command */
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 4;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the first command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the second command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 7 --------------------------------------------------------------------*/
/* Program the external memory mode register */
tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
/* Configure a load Mode register command*/
FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_LoadMode;
FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr;
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
/* Send the command */
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
/* Step 8 --------------------------------------------------------------------*/
/* Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
/* Set the device refresh counter */
FMC_SetRefreshCount(1386);
/* Wait until the SDRAM controller is ready */
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
}
void SDRAM_Init(void)
{
FMC_SDRAMInitTypeDef FMC_SDRAMInitStructure;
FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingInitStructure;
/* GPIO configuration for FMC SDRAM bank */
SDRAM_GPIOConfig();
/* Enable FMC clock */
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);
/* FMC Configuration ---------------------------------------------------------*/
/* FMC SDRAM Bank configuration */
/* Timing configuration for 90 Mhz of SD clock frequency (168Mhz/2) */
/* TMRD: 2 Clock cycles */
FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2;
/* TXSR: min=70ns (7x11.11ns) */
FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7;
/* TRAS: min=42ns (4x11.11ns) max=120k (ns) */
FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4;
/* TRC: min=70 (7x11.11ns) */
FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 7;
/* TWR: min=1+ 7ns (1+1x11.11ns) */
FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 2;
/* TRP: 20ns => 2x11.11ns */
FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2;
/* TRCD: 20ns => 2x11.11ns */
FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2;
/* FMC SDRAM control configuration */
FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank2_SDRAM;
/* Row addressing: [7:0] */
FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;
/* Column addressing: [11:0] */
FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_12b;
FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = SDRAM_MEMORY_WIDTH;
FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
FMC_SDRAMInitStructure.FMC_CASLatency = SDRAM_CAS_LATENCY;
FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable;
FMC_SDRAMInitStructure.FMC_SDClockPeriod = SDCLOCK_PERIOD;
FMC_SDRAMInitStructure.FMC_ReadBurst = SDRAM_READBURST;
FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_0;
FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingInitStructure;
/* FMC SDRAM bank initialization */
FMC_SDRAMInit(&FMC_SDRAMInitStructure);
/* FMC SDRAM device initialization sequence */
SDRAMTest_InitSequence();
}
#if 0
void SDRAM_WriteBuffer(uint32_t* pBuffer, uint32_t uwWriteAddress, uint32_t uwBufferSize)
{
__IO uint32_t write_pointer = (uint32_t)uwWriteAddress;
FMC_SDRAMWriteProtectionConfig(FMC_Bank1_SDRAM, DISABLE);
while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
for (; uwBufferSize != 0; uwBufferSize--)
{
*(uint32_t *) (SDRAM_BANK_ADDR + write_pointer) = *pBuffer++;
write_pointer += 4;
}
}
void SDRAM_ReadBuffer(uint32_t* pBuffer, uint32_t uwReadAddress, uint32_t uwBufferSize)
{
__IO uint32_t write_pointer = (uint32_t)uwReadAddress;
while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
for(; uwBufferSize != 0x00; uwBufferSize--)
{
*pBuffer++ = *(__IO uint32_t *)(SDRAM_BANK_ADDR + write_pointer );
write_pointer += 4;
}
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,232 +1,232 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
Fifo<uint8_t, TELEMETRY_FIFO_SIZE> telemetryNoDMAFifo;
uint32_t telemetryErrors = 0;
#if defined(PCBX12S)
DMAFifo<TELEMETRY_FIFO_SIZE> telemetryDMAFifo __DMA (TELEMETRY_DMA_Stream_RX);
uint8_t telemetryFifoMode;
#endif
void telemetryPortInit(uint32_t baudrate, uint8_t mode)
{
if (baudrate == 0) {
USART_DeInit(TELEMETRY_USART);
return;
}
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TELEMETRY_DMA_TX_Stream_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_RX, TELEMETRY_GPIO_AF);
GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_TX, TELEMETRY_GPIO_AF);
GPIO_InitStructure.GPIO_Pin = TELEMETRY_TX_GPIO_PIN | TELEMETRY_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN);
USART_InitStructure.USART_BaudRate = baudrate;
if (mode & TELEMETRY_SERIAL_8E2) {
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
USART_InitStructure.USART_StopBits = USART_StopBits_2;
USART_InitStructure.USART_Parity = USART_Parity_Even;
}
else {
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
}
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(TELEMETRY_USART, &USART_InitStructure);
#if defined(PCBX12S)
telemetryFifoMode = mode;
DMA_Cmd(TELEMETRY_DMA_Stream_RX, DISABLE);
USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Rx, DISABLE);
DMA_DeInit(TELEMETRY_DMA_Stream_RX);
if (mode & TELEMETRY_SERIAL_WITHOUT_DMA) {
USART_Cmd(TELEMETRY_USART, ENABLE);
USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, ENABLE);
NVIC_SetPriority(TELEMETRY_USART_IRQn, 6);
NVIC_EnableIRQ(TELEMETRY_USART_IRQn);
}
else {
DMA_InitTypeDef DMA_InitStructure;
telemetryDMAFifo.clear();
USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, DISABLE);
USART_ITConfig(TELEMETRY_USART, USART_IT_TXE, DISABLE);
NVIC_SetPriority(TELEMETRY_USART_IRQn, 6);
NVIC_EnableIRQ(TELEMETRY_USART_IRQn);
DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_RX;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(telemetryDMAFifo.buffer());
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = telemetryDMAFifo.size();
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(TELEMETRY_DMA_Stream_RX, &DMA_InitStructure);
USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Rx, ENABLE);
USART_Cmd(TELEMETRY_USART, ENABLE);
DMA_Cmd(TELEMETRY_DMA_Stream_RX, ENABLE);
}
#else
USART_Cmd(TELEMETRY_USART, ENABLE);
USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, ENABLE);
NVIC_SetPriority(TELEMETRY_USART_IRQn, 6);
NVIC_EnableIRQ(TELEMETRY_USART_IRQn);
#endif
}
void telemetryPortSetDirectionOutput()
{
TELEMETRY_DIR_GPIO->BSRRL = TELEMETRY_DIR_GPIO_PIN; // output enable
TELEMETRY_USART->CR1 &= ~USART_CR1_RE; // turn off receiver
}
void telemetryPortSetDirectionInput()
{
TELEMETRY_DIR_GPIO->BSRRH = TELEMETRY_DIR_GPIO_PIN; // output disable
TELEMETRY_USART->CR1 |= USART_CR1_RE; // turn on receiver
}
void sportSendBuffer(uint8_t * buffer, uint32_t count)
{
telemetryPortSetDirectionOutput();
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(TELEMETRY_DMA_Stream_TX);
DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_TX;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR);
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(buffer);
DMA_InitStructure.DMA_BufferSize = count;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(TELEMETRY_DMA_Stream_TX, &DMA_InitStructure);
DMA_Cmd(TELEMETRY_DMA_Stream_TX, ENABLE);
USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Tx, ENABLE);
DMA_ITConfig(TELEMETRY_DMA_Stream_TX, DMA_IT_TC, ENABLE);
// enable interrupt and set it's priority
NVIC_EnableIRQ(TELEMETRY_DMA_TX_Stream_IRQ) ;
NVIC_SetPriority(TELEMETRY_DMA_TX_Stream_IRQ, 7);
}
extern "C" void TELEMETRY_DMA_TX_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_TELEM_DMA);
if (DMA_GetITStatus(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC)) {
DMA_ClearITPendingBit(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC);
TELEMETRY_USART->CR1 |= USART_CR1_TCIE;
if (telemetryProtocol == PROTOCOL_FRSKY_SPORT) {
outputTelemetryBufferSize = 0;
outputTelemetryBufferTrigger = 0x7E;
}
}
}
#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE)
extern "C" void TELEMETRY_USART_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_TELEM_USART);
uint32_t status = TELEMETRY_USART->SR;
if ((status & USART_SR_TC) && (TELEMETRY_USART->CR1 & USART_CR1_TCIE)) {
TELEMETRY_USART->CR1 &= ~USART_CR1_TCIE;
telemetryPortSetDirectionInput();
while (status & (USART_FLAG_RXNE)) {
status = TELEMETRY_USART->DR;
status = TELEMETRY_USART->SR;
}
}
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
uint8_t data = TELEMETRY_USART->DR;
if (status & USART_FLAG_ERRORS) {
telemetryErrors++;
}
else {
telemetryNoDMAFifo.push(data);
#if defined(LUA)
if (telemetryProtocol == PROTOCOL_FRSKY_SPORT) {
static uint8_t prevdata;
if (prevdata == 0x7E && outputTelemetryBufferSize > 0 && data == outputTelemetryBufferTrigger) {
sportSendBuffer(outputTelemetryBuffer, outputTelemetryBufferSize);
}
prevdata = data;
}
#endif
}
status = TELEMETRY_USART->SR;
}
}
// TODO we should have telemetry in an higher layer, functions above should move to a sport_driver.cpp
uint8_t telemetryGetByte(uint8_t * byte)
{
#if defined(PCBX12S)
if (telemetryFifoMode & TELEMETRY_SERIAL_WITHOUT_DMA)
return telemetryNoDMAFifo.pop(*byte);
else
return telemetryDMAFifo.pop(*byte);
#else
return telemetryNoDMAFifo.pop(*byte);
#endif
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
Fifo<uint8_t, TELEMETRY_FIFO_SIZE> telemetryNoDMAFifo;
uint32_t telemetryErrors = 0;
#if defined(PCBX12S)
DMAFifo<TELEMETRY_FIFO_SIZE> telemetryDMAFifo __DMA (TELEMETRY_DMA_Stream_RX);
uint8_t telemetryFifoMode;
#endif
void telemetryPortInit(uint32_t baudrate, uint8_t mode)
{
if (baudrate == 0) {
USART_DeInit(TELEMETRY_USART);
return;
}
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TELEMETRY_DMA_TX_Stream_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_RX, TELEMETRY_GPIO_AF);
GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_TX, TELEMETRY_GPIO_AF);
GPIO_InitStructure.GPIO_Pin = TELEMETRY_TX_GPIO_PIN | TELEMETRY_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN);
USART_InitStructure.USART_BaudRate = baudrate;
if (mode & TELEMETRY_SERIAL_8E2) {
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
USART_InitStructure.USART_StopBits = USART_StopBits_2;
USART_InitStructure.USART_Parity = USART_Parity_Even;
}
else {
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
}
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(TELEMETRY_USART, &USART_InitStructure);
#if defined(PCBX12S)
telemetryFifoMode = mode;
DMA_Cmd(TELEMETRY_DMA_Stream_RX, DISABLE);
USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Rx, DISABLE);
DMA_DeInit(TELEMETRY_DMA_Stream_RX);
if (mode & TELEMETRY_SERIAL_WITHOUT_DMA) {
USART_Cmd(TELEMETRY_USART, ENABLE);
USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, ENABLE);
NVIC_SetPriority(TELEMETRY_USART_IRQn, 6);
NVIC_EnableIRQ(TELEMETRY_USART_IRQn);
}
else {
DMA_InitTypeDef DMA_InitStructure;
telemetryDMAFifo.clear();
USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, DISABLE);
USART_ITConfig(TELEMETRY_USART, USART_IT_TXE, DISABLE);
NVIC_SetPriority(TELEMETRY_USART_IRQn, 6);
NVIC_EnableIRQ(TELEMETRY_USART_IRQn);
DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_RX;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(telemetryDMAFifo.buffer());
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = telemetryDMAFifo.size();
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(TELEMETRY_DMA_Stream_RX, &DMA_InitStructure);
USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Rx, ENABLE);
USART_Cmd(TELEMETRY_USART, ENABLE);
DMA_Cmd(TELEMETRY_DMA_Stream_RX, ENABLE);
}
#else
USART_Cmd(TELEMETRY_USART, ENABLE);
USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, ENABLE);
NVIC_SetPriority(TELEMETRY_USART_IRQn, 6);
NVIC_EnableIRQ(TELEMETRY_USART_IRQn);
#endif
}
void telemetryPortSetDirectionOutput()
{
TELEMETRY_DIR_GPIO->BSRRL = TELEMETRY_DIR_GPIO_PIN; // output enable
TELEMETRY_USART->CR1 &= ~USART_CR1_RE; // turn off receiver
}
void telemetryPortSetDirectionInput()
{
TELEMETRY_DIR_GPIO->BSRRH = TELEMETRY_DIR_GPIO_PIN; // output disable
TELEMETRY_USART->CR1 |= USART_CR1_RE; // turn on receiver
}
void sportSendBuffer(uint8_t * buffer, uint32_t count)
{
telemetryPortSetDirectionOutput();
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(TELEMETRY_DMA_Stream_TX);
DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_TX;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR);
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(buffer);
DMA_InitStructure.DMA_BufferSize = count;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(TELEMETRY_DMA_Stream_TX, &DMA_InitStructure);
DMA_Cmd(TELEMETRY_DMA_Stream_TX, ENABLE);
USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Tx, ENABLE);
DMA_ITConfig(TELEMETRY_DMA_Stream_TX, DMA_IT_TC, ENABLE);
// enable interrupt and set it's priority
NVIC_EnableIRQ(TELEMETRY_DMA_TX_Stream_IRQ) ;
NVIC_SetPriority(TELEMETRY_DMA_TX_Stream_IRQ, 7);
}
extern "C" void TELEMETRY_DMA_TX_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_TELEM_DMA);
if (DMA_GetITStatus(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC)) {
DMA_ClearITPendingBit(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC);
TELEMETRY_USART->CR1 |= USART_CR1_TCIE;
if (telemetryProtocol == PROTOCOL_FRSKY_SPORT) {
outputTelemetryBufferSize = 0;
outputTelemetryBufferTrigger = 0x7E;
}
}
}
#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE)
extern "C" void TELEMETRY_USART_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_TELEM_USART);
uint32_t status = TELEMETRY_USART->SR;
if ((status & USART_SR_TC) && (TELEMETRY_USART->CR1 & USART_CR1_TCIE)) {
TELEMETRY_USART->CR1 &= ~USART_CR1_TCIE;
telemetryPortSetDirectionInput();
while (status & (USART_FLAG_RXNE)) {
status = TELEMETRY_USART->DR;
status = TELEMETRY_USART->SR;
}
}
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
uint8_t data = TELEMETRY_USART->DR;
if (status & USART_FLAG_ERRORS) {
telemetryErrors++;
}
else {
telemetryNoDMAFifo.push(data);
#if defined(LUA)
if (telemetryProtocol == PROTOCOL_FRSKY_SPORT) {
static uint8_t prevdata;
if (prevdata == 0x7E && outputTelemetryBufferSize > 0 && data == outputTelemetryBufferTrigger) {
sportSendBuffer(outputTelemetryBuffer, outputTelemetryBufferSize);
}
prevdata = data;
}
#endif
}
status = TELEMETRY_USART->SR;
}
}
// TODO we should have telemetry in an higher layer, functions above should move to a sport_driver.cpp
uint8_t telemetryGetByte(uint8_t * byte)
{
#if defined(PCBX12S)
if (telemetryFifoMode & TELEMETRY_SERIAL_WITHOUT_DMA)
return telemetryNoDMAFifo.pop(*byte);
else
return telemetryDMAFifo.pop(*byte);
#else
return telemetryNoDMAFifo.pop(*byte);
#endif
}

View file

@ -1,154 +1,154 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void trainerSendNextFrame();
void init_trainer_ppm()
{
GPIO_PinAFConfig(TRAINER_GPIO, TRAINER_OUT_GPIO_PinSource, TRAINER_GPIO_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = TRAINER_OUT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(TRAINER_GPIO, &GPIO_InitStructure);
TRAINER_TIMER->CR1 &= ~TIM_CR1_CEN;
TRAINER_TIMER->PSC = TRAINER_TIMER_FREQ / 2000000 - 1; // 0.5uS
TRAINER_TIMER->ARR = 45000;
TRAINER_TIMER->CCR2 = GET_PPM_DELAY(TRAINER_MODULE)*2;
TRAINER_TIMER->CCER = TIM_CCER_CC2E | (g_model.moduleData[TRAINER_MODULE].ppm.pulsePol ? 0 : TIM_CCER_CC2P);
TRAINER_TIMER->CCMR1 = TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_0; // Force O/P high
TRAINER_TIMER->BDTR = TIM_BDTR_MOE;
TRAINER_TIMER->EGR = 1;
TRAINER_TIMER->DIER |= TIM_DIER_UDE;
TRAINER_TIMER->CCMR1 = TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2PE; // PWM mode 1
TRAINER_TIMER->CR1 |= TIM_CR1_CEN;
setupPulsesPPMTrainer();
trainerSendNextFrame();
NVIC_EnableIRQ(TRAINER_DMA_IRQn);
NVIC_SetPriority(TRAINER_DMA_IRQn, 7);
NVIC_EnableIRQ(TRAINER_TIMER_IRQn);
NVIC_SetPriority(TRAINER_TIMER_IRQn, 7);
}
void stop_trainer_ppm()
{
NVIC_DisableIRQ(TRAINER_DMA_IRQn);
NVIC_DisableIRQ(TRAINER_TIMER_IRQn);
TRAINER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
TRAINER_TIMER->DIER = 0; // Stop Interrupt
TRAINER_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop counter
}
void init_trainer_capture()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = TRAINER_IN_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(TRAINER_GPIO, &GPIO_InitStructure);
GPIO_PinAFConfig(TRAINER_GPIO, TRAINER_IN_GPIO_PinSource, TRAINER_GPIO_AF);
TRAINER_TIMER->ARR = 0xFFFF;
TRAINER_TIMER->PSC = TRAINER_TIMER_FREQ / 2000000 - 1; // 0.5uS
TRAINER_TIMER->CR2 = 0;
TRAINER_TIMER->CCMR1 = TIM_CCMR1_IC1F_0 | TIM_CCMR1_IC1F_1 | TIM_CCMR1_CC1S_0;
TRAINER_TIMER->CCER = TIM_CCER_CC1E;
TRAINER_TIMER->SR &= ~TIM_SR_CC1IF & ~TIM_SR_CC2IF & ~TIM_SR_UIF; // Clear flags
TRAINER_TIMER->DIER |= TIM_DIER_CC1IE;
TRAINER_TIMER->CR1 = TIM_CR1_CEN;
NVIC_EnableIRQ(TRAINER_TIMER_IRQn);
NVIC_SetPriority(TRAINER_TIMER_IRQn, 7);
}
void stop_trainer_capture()
{
NVIC_DisableIRQ(TRAINER_TIMER_IRQn); // Stop Interrupt
TRAINER_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop counter
TRAINER_TIMER->DIER = 0; // Stop Interrupt
}
void trainerSendNextFrame()
{
TRAINER_TIMER->CCR2 = GET_PPM_DELAY(TRAINER_MODULE)*2;
TRAINER_TIMER->CCER = TIM_CCER_CC2E | (g_model.moduleData[TRAINER_MODULE].ppm.pulsePol ? 0 : TIM_CCER_CC2P);
TRAINER_TIMER->CCR1 = *(trainerPulsesData.ppm.ptr - 1) - 4000; // 2mS in advance
TRAINER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
TRAINER_DMA_STREAM->CR |= TRAINER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
TRAINER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&TRAINER_TIMER->ARR);
TRAINER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(trainerPulsesData.ppm.pulses);
TRAINER_DMA_STREAM->NDTR = trainerPulsesData.ppm.ptr - trainerPulsesData.ppm.pulses;
TRAINER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
}
extern "C" void TRAINER_DMA_IRQHandler()
{
if (!DMA_GetITStatus(TRAINER_DMA_STREAM, TRAINER_DMA_FLAG_TC))
return;
DMA_ClearITPendingBit(TRAINER_DMA_STREAM, TRAINER_DMA_FLAG_TC);
TRAINER_TIMER->SR &= ~TIM_SR_CC1IF; // Clear flag
TRAINER_TIMER->DIER |= TIM_DIER_CC1IE; // Enable this interrupt
}
extern "C" void TRAINER_TIMER_IRQHandler()
{
DEBUG_INTERRUPT(INT_TRAINER);
uint16_t capture = 0;
bool doCapture = false;
// What mode? in or out?
if ((TRAINER_TIMER->DIER & TIM_DIER_CC1IE) && (TRAINER_TIMER->SR & TIM_SR_CC1IF)) {
// capture mode on trainer jack
capture = TRAINER_TIMER->CCR1;
if (TRAINER_CONNECTED() && currentTrainerMode == TRAINER_MODE_MASTER_TRAINER_JACK) {
doCapture = true;
}
}
if (doCapture) {
captureTrainerPulses(capture);
}
// PPM out compare interrupt
if ((TRAINER_TIMER->DIER & TIM_DIER_CC1IE) && (TRAINER_TIMER->SR & TIM_SR_CC1IF)) {
// compare interrupt
TRAINER_TIMER->DIER &= ~TIM_DIER_CC1IE; // stop this interrupt
TRAINER_TIMER->SR &= ~TIM_SR_CC1IF; // Clear flag
setupPulsesPPMTrainer();
trainerSendNextFrame();
}
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void trainerSendNextFrame();
void init_trainer_ppm()
{
GPIO_PinAFConfig(TRAINER_GPIO, TRAINER_OUT_GPIO_PinSource, TRAINER_GPIO_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = TRAINER_OUT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(TRAINER_GPIO, &GPIO_InitStructure);
TRAINER_TIMER->CR1 &= ~TIM_CR1_CEN;
TRAINER_TIMER->PSC = TRAINER_TIMER_FREQ / 2000000 - 1; // 0.5uS
TRAINER_TIMER->ARR = 45000;
TRAINER_TIMER->CCR2 = GET_PPM_DELAY(TRAINER_MODULE)*2;
TRAINER_TIMER->CCER = TIM_CCER_CC2E | (g_model.moduleData[TRAINER_MODULE].ppm.pulsePol ? 0 : TIM_CCER_CC2P);
TRAINER_TIMER->CCMR1 = TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_0; // Force O/P high
TRAINER_TIMER->BDTR = TIM_BDTR_MOE;
TRAINER_TIMER->EGR = 1;
TRAINER_TIMER->DIER |= TIM_DIER_UDE;
TRAINER_TIMER->CCMR1 = TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2PE; // PWM mode 1
TRAINER_TIMER->CR1 |= TIM_CR1_CEN;
setupPulsesPPMTrainer();
trainerSendNextFrame();
NVIC_EnableIRQ(TRAINER_DMA_IRQn);
NVIC_SetPriority(TRAINER_DMA_IRQn, 7);
NVIC_EnableIRQ(TRAINER_TIMER_IRQn);
NVIC_SetPriority(TRAINER_TIMER_IRQn, 7);
}
void stop_trainer_ppm()
{
NVIC_DisableIRQ(TRAINER_DMA_IRQn);
NVIC_DisableIRQ(TRAINER_TIMER_IRQn);
TRAINER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
TRAINER_TIMER->DIER = 0; // Stop Interrupt
TRAINER_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop counter
}
void init_trainer_capture()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = TRAINER_IN_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(TRAINER_GPIO, &GPIO_InitStructure);
GPIO_PinAFConfig(TRAINER_GPIO, TRAINER_IN_GPIO_PinSource, TRAINER_GPIO_AF);
TRAINER_TIMER->ARR = 0xFFFF;
TRAINER_TIMER->PSC = TRAINER_TIMER_FREQ / 2000000 - 1; // 0.5uS
TRAINER_TIMER->CR2 = 0;
TRAINER_TIMER->CCMR1 = TIM_CCMR1_IC1F_0 | TIM_CCMR1_IC1F_1 | TIM_CCMR1_CC1S_0;
TRAINER_TIMER->CCER = TIM_CCER_CC1E;
TRAINER_TIMER->SR &= ~TIM_SR_CC1IF & ~TIM_SR_CC2IF & ~TIM_SR_UIF; // Clear flags
TRAINER_TIMER->DIER |= TIM_DIER_CC1IE;
TRAINER_TIMER->CR1 = TIM_CR1_CEN;
NVIC_EnableIRQ(TRAINER_TIMER_IRQn);
NVIC_SetPriority(TRAINER_TIMER_IRQn, 7);
}
void stop_trainer_capture()
{
NVIC_DisableIRQ(TRAINER_TIMER_IRQn); // Stop Interrupt
TRAINER_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop counter
TRAINER_TIMER->DIER = 0; // Stop Interrupt
}
void trainerSendNextFrame()
{
TRAINER_TIMER->CCR2 = GET_PPM_DELAY(TRAINER_MODULE)*2;
TRAINER_TIMER->CCER = TIM_CCER_CC2E | (g_model.moduleData[TRAINER_MODULE].ppm.pulsePol ? 0 : TIM_CCER_CC2P);
TRAINER_TIMER->CCR1 = *(trainerPulsesData.ppm.ptr - 1) - 4000; // 2mS in advance
TRAINER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
TRAINER_DMA_STREAM->CR |= TRAINER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
TRAINER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&TRAINER_TIMER->ARR);
TRAINER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(trainerPulsesData.ppm.pulses);
TRAINER_DMA_STREAM->NDTR = trainerPulsesData.ppm.ptr - trainerPulsesData.ppm.pulses;
TRAINER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
}
extern "C" void TRAINER_DMA_IRQHandler()
{
if (!DMA_GetITStatus(TRAINER_DMA_STREAM, TRAINER_DMA_FLAG_TC))
return;
DMA_ClearITPendingBit(TRAINER_DMA_STREAM, TRAINER_DMA_FLAG_TC);
TRAINER_TIMER->SR &= ~TIM_SR_CC1IF; // Clear flag
TRAINER_TIMER->DIER |= TIM_DIER_CC1IE; // Enable this interrupt
}
extern "C" void TRAINER_TIMER_IRQHandler()
{
DEBUG_INTERRUPT(INT_TRAINER);
uint16_t capture = 0;
bool doCapture = false;
// What mode? in or out?
if ((TRAINER_TIMER->DIER & TIM_DIER_CC1IE) && (TRAINER_TIMER->SR & TIM_SR_CC1IF)) {
// capture mode on trainer jack
capture = TRAINER_TIMER->CCR1;
if (TRAINER_CONNECTED() && currentTrainerMode == TRAINER_MODE_MASTER_TRAINER_JACK) {
doCapture = true;
}
}
if (doCapture) {
captureTrainerPulses(capture);
}
// PPM out compare interrupt
if ((TRAINER_TIMER->DIER & TIM_DIER_CC1IE) && (TRAINER_TIMER->SR & TIM_SR_CC1IF)) {
// compare interrupt
TRAINER_TIMER->DIER &= ~TIM_DIER_CC1IE; // stop this interrupt
TRAINER_TIMER->SR &= ~TIM_SR_CC1IF; // Clear flag
setupPulsesPPMTrainer();
trainerSendNextFrame();
}
}

View file

@ -1,8 +1,8 @@
MEGA2560 board
======================= DESCRIPTION =======================
DIY radio wih :
- Arduino MEGA2560 or compatible
- Gruvin9x features (soft-off, SD-Card, RTC, haptic, voice, rotary encoders)
- LCD 128x64 8 bits parallel mode
MEGA2560 board
======================= DESCRIPTION =======================
DIY radio wih :
- Arduino MEGA2560 or compatible
- Gruvin9x features (soft-off, SD-Card, RTC, haptic, voice, rotary encoders)
- LCD 128x64 8 bits parallel mode
- home made case

View file

@ -1,196 +1,196 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BOARD_MEGA2560_H_
#define _BOARD_MEGA2560_H_
#include "../common/avr/board_avr.h"
// Board driver
void boardInit(void);
#define boardOff() pwrOff()
// Keys
#define KEYS_GPIO_REG_MENU pinl
#define KEYS_GPIO_PIN_MENU (1<<4)
#define KEYS_GPIO_REG_EXIT pinl
#define KEYS_GPIO_PIN_EXIT (1<<5)
#define KEYS_GPIO_REG_RIGHT pinl
#define KEYS_GPIO_PIN_RIGHT (1<<2)
#define KEYS_GPIO_REG_LEFT pinl
#define KEYS_GPIO_PIN_LEFT (1<<3)
#define KEYS_GPIO_REG_UP pinl
#define KEYS_GPIO_PIN_UP (1<<1)
#define KEYS_GPIO_REG_DOWN pinl
#define KEYS_GPIO_PIN_DOWN (1<<0)
// Trims
#define TRIMS_GPIO_REG_LHL pinf
#define TRIMS_GPIO_PIN_LHL (1<<7)
#define TRIMS_GPIO_REG_LVD pinf
#define TRIMS_GPIO_PIN_LVD (1<<5)
#define TRIMS_GPIO_REG_RVU pinf
#define TRIMS_GPIO_PIN_RVU (1<<2)
#define TRIMS_GPIO_REG_RHL pinf
#define TRIMS_GPIO_PIN_RHL (1<<1)
#define TRIMS_GPIO_REG_LHR pinf
#define TRIMS_GPIO_PIN_LHR (1<<6)
#define TRIMS_GPIO_REG_LVU pinf
#define TRIMS_GPIO_PIN_LVU (1<<4)
#define TRIMS_GPIO_REG_RVD pinf
#define TRIMS_GPIO_PIN_RVD (1<<3)
#define TRIMS_GPIO_REG_RHR pinf
#define TRIMS_GPIO_PIN_RHR (1<<0)
#define TIMER_16KHZ_VECT TIMER2_OVF_vect
#define COUNTER_16KHZ TCNT2
#define TIMER_10MS_VECT TIMER2_COMPA_vect
#define TIMER_10MS_COMPVAL OCR2A
#define PAUSE_10MS_INTERRUPT() TIMSK2 &= ~(1<<OCIE2A)
#define RESUME_10MS_INTERRUPT() TIMSK2 |= (1<<OCIE2A)
#define PAUSE_PPMIN_INTERRUPT() TIMSK3 &= ~(1<<ICIE3)
#define RESUME_PPMIN_INTERRUPT() TIMSK3 |= (1<<ICIE3)
#define SLAVE_MODE() ~PINH & (1<<INP_H_RF_Activated)
#define JACK_PPM_OUT() PORTB &= ~(1<<OUT_B_SIM_CTL)
#define JACK_PPM_IN() PORTB |= (1<<OUT_B_SIM_CTL)
// Backlight driver
#define backlightEnable() PORTC |= (1<<OUT_C_LIGHT)
#define backlightDisable() PORTC &= ~(1<<OUT_C_LIGHT)
#define isBacklightEnabled() PORTC & (1<<OUT_C_LIGHT)
#define BACKLIGHT_ENABLE() backlightEnable()
#define BACKLIGHT_DISABLE() backlightDisable()
// SD driver
#define BLOCK_SIZE 512 /* Block Size in Bytes */
#define sdDone()
#define SD_IS_HC() (0)
#define SD_GET_SPEED() (0)
#if !defined(SIMU)
bool sdMounted(void);
void sdMountPoll(void);
void sdPoll10ms(void);
#endif
// Switchs driver
#define INP_C_ID2 1
#define INP_C_ID1 0
#define INP_D_AileDR 7
#define INP_G_ThrCt 2
#define INP_G_Gear 1
#define INP_G_RuddDR 0
#define INP_L_ElevDR 6
#define INP_L_Trainer 7
// Servitudes driver
#define INP_E_PPM_IN 7 //directly used
#define INP_B_VoiceBuzy 7 //directly used
#define OUT_B_PPM 6
#define OUT_B_SIM_CTL 5
#define I_O_B_UNUSED 4 //unused, was Buzzer
#define INP_D_I2C_SCL 1
#define INP_D_I2C_SDA 0
#define OUT_E_VoiceData 3
#define INP_E_TELEM_RX 1
#define OUT_E_TELEM_TX 0
#define OUT_G_VoiceClock 5
#define INP_H_RF_Activated 6
#define INP_H_DSC_Activated 5 //pwrCheck(), directly used
#define INP_H_Hold_Power 4 //pwrCheck(), directly used
#define OUT_H_SpeakerBuzzer 3
#define OUT_H_VoiceReset 1
#define OUT_H_HAPTIC 0
// Rotary encoders driver
#define INP_E_ROT_ENC_1_A 4
#define INP_E_ROT_ENC_1_B 5
#define INP_D_ROT_ENC_2_A 2
#define INP_D_ROT_ENC_2_B 3
#define INP_J_ROT_ENC_1_PUSH 0
#define INP_J_ROT_ENC_2_PUSH 1
#define REA_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_1_PUSH))
#define REB_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_2_PUSH))
#define ROTENC_DOWN() (REA_DOWN() || REB_DOWN())
#define ROTENC_DIV2 // rotary encoders resolution/2
// LCD driver
#define PORTA_LCD_DAT PORTA
#define PORTC_LCD_CTRL PORTC
#if defined(LCD_KS108) // (For KS108 LCD only) MEGA R/W pin always at 0 state in Opentx then
#define OUT_C_LCD_CS2 6 // use this pin to control second KS108 (CS2)
#else // and connect KS108 R/W pin to ground via a 1k resistor
#define OUT_C_LCD_RnW 6
#endif
#define OUT_C_LCD_E 7
#define OUT_C_LCD_A0 5
#define OUT_C_LCD_RES 4
#define OUT_C_LCD_CS1 3
#define OUT_C_LIGHT 2
// DBLKeys driver
#define KEYS_PRESSED() (~PINL)
// Power driver
uint8_t pwrCheck();
void pwrOff();
#if defined(PWRMANAGE)
#define UNEXPECTED_SHUTDOWN() ((mcusr & (1 << WDRF)) || g_eeGeneral.unexpectedShutdown)
#else
#define UNEXPECTED_SHUTDOWN() (mcusr & (1 << WDRF))
#endif
// USB fake driver
#define usbPlugged() false
// Haptic driver
#define hapticOn() PORTH |= (1 << OUT_H_HAPTIC)
#define hapticOff() PORTH &= ~(1 << OUT_H_HAPTIC)
// Buzzer driver
#define buzzerOn() PORTH |= (1 << OUT_H_SpeakerBuzzer)
#define buzzerOff() PORTH &= ~(1 << OUT_H_SpeakerBuzzer)
// Speaker driver
#if defined(AUDIO)
#define speakerOn() TCCR4A |= (1 << COM4A0)
#define speakerOff() TCCR4A &= ~(1 << COM4A0)
#endif
// Voice driver (WTV20)
#if defined(VOICE_WTV20)
#define WTV20_Data_on PORTE |= (1<<OUT_E_VoiceData)
#define WTV20_Data_off PORTE &= ~(1<<OUT_E_VoiceData)
#define WTV20_BUSY (PINB & (1<<INP_B_VoiceBuzy))
#define WTV20_Clock_on PORTG |= (1<<OUT_G_VoiceClock)
#define WTV20_Clock_off PORTG &= ~(1<<OUT_G_VoiceClock)
#define WTV20_CLK (PING & (1<<OUT_G_VoiceClock))
#define WTV20_Reset_on PORTH |= (1<<OUT_H_VoiceReset)
#define WTV20_Reset_off PORTH &= ~(1<<OUT_H_VoiceReset)
#endif
// Voice driver (JQ6500)
#if defined(VOICE_JQ6500)
#define JQ6500_Serial_on PORTE |= (1<<OUT_E_VoiceData)
#define JQ6500_Serial_off PORTE &= ~(1<<OUT_E_VoiceData)
#define JQ6500_BUSY (PINB & (1<<INP_B_VoiceBuzy))
#endif
#endif // _BOARD_MEGA2560_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BOARD_MEGA2560_H_
#define _BOARD_MEGA2560_H_
#include "../common/avr/board_avr.h"
// Board driver
void boardInit(void);
#define boardOff() pwrOff()
// Keys
#define KEYS_GPIO_REG_MENU pinl
#define KEYS_GPIO_PIN_MENU (1<<4)
#define KEYS_GPIO_REG_EXIT pinl
#define KEYS_GPIO_PIN_EXIT (1<<5)
#define KEYS_GPIO_REG_RIGHT pinl
#define KEYS_GPIO_PIN_RIGHT (1<<2)
#define KEYS_GPIO_REG_LEFT pinl
#define KEYS_GPIO_PIN_LEFT (1<<3)
#define KEYS_GPIO_REG_UP pinl
#define KEYS_GPIO_PIN_UP (1<<1)
#define KEYS_GPIO_REG_DOWN pinl
#define KEYS_GPIO_PIN_DOWN (1<<0)
// Trims
#define TRIMS_GPIO_REG_LHL pinf
#define TRIMS_GPIO_PIN_LHL (1<<7)
#define TRIMS_GPIO_REG_LVD pinf
#define TRIMS_GPIO_PIN_LVD (1<<5)
#define TRIMS_GPIO_REG_RVU pinf
#define TRIMS_GPIO_PIN_RVU (1<<2)
#define TRIMS_GPIO_REG_RHL pinf
#define TRIMS_GPIO_PIN_RHL (1<<1)
#define TRIMS_GPIO_REG_LHR pinf
#define TRIMS_GPIO_PIN_LHR (1<<6)
#define TRIMS_GPIO_REG_LVU pinf
#define TRIMS_GPIO_PIN_LVU (1<<4)
#define TRIMS_GPIO_REG_RVD pinf
#define TRIMS_GPIO_PIN_RVD (1<<3)
#define TRIMS_GPIO_REG_RHR pinf
#define TRIMS_GPIO_PIN_RHR (1<<0)
#define TIMER_16KHZ_VECT TIMER2_OVF_vect
#define COUNTER_16KHZ TCNT2
#define TIMER_10MS_VECT TIMER2_COMPA_vect
#define TIMER_10MS_COMPVAL OCR2A
#define PAUSE_10MS_INTERRUPT() TIMSK2 &= ~(1<<OCIE2A)
#define RESUME_10MS_INTERRUPT() TIMSK2 |= (1<<OCIE2A)
#define PAUSE_PPMIN_INTERRUPT() TIMSK3 &= ~(1<<ICIE3)
#define RESUME_PPMIN_INTERRUPT() TIMSK3 |= (1<<ICIE3)
#define SLAVE_MODE() ~PINH & (1<<INP_H_RF_Activated)
#define JACK_PPM_OUT() PORTB &= ~(1<<OUT_B_SIM_CTL)
#define JACK_PPM_IN() PORTB |= (1<<OUT_B_SIM_CTL)
// Backlight driver
#define backlightEnable() PORTC |= (1<<OUT_C_LIGHT)
#define backlightDisable() PORTC &= ~(1<<OUT_C_LIGHT)
#define isBacklightEnabled() PORTC & (1<<OUT_C_LIGHT)
#define BACKLIGHT_ENABLE() backlightEnable()
#define BACKLIGHT_DISABLE() backlightDisable()
// SD driver
#define BLOCK_SIZE 512 /* Block Size in Bytes */
#define sdDone()
#define SD_IS_HC() (0)
#define SD_GET_SPEED() (0)
#if !defined(SIMU)
bool sdMounted(void);
void sdMountPoll(void);
void sdPoll10ms(void);
#endif
// Switchs driver
#define INP_C_ID2 1
#define INP_C_ID1 0
#define INP_D_AileDR 7
#define INP_G_ThrCt 2
#define INP_G_Gear 1
#define INP_G_RuddDR 0
#define INP_L_ElevDR 6
#define INP_L_Trainer 7
// Servitudes driver
#define INP_E_PPM_IN 7 //directly used
#define INP_B_VoiceBuzy 7 //directly used
#define OUT_B_PPM 6
#define OUT_B_SIM_CTL 5
#define I_O_B_UNUSED 4 //unused, was Buzzer
#define INP_D_I2C_SCL 1
#define INP_D_I2C_SDA 0
#define OUT_E_VoiceData 3
#define INP_E_TELEM_RX 1
#define OUT_E_TELEM_TX 0
#define OUT_G_VoiceClock 5
#define INP_H_RF_Activated 6
#define INP_H_DSC_Activated 5 //pwrCheck(), directly used
#define INP_H_Hold_Power 4 //pwrCheck(), directly used
#define OUT_H_SpeakerBuzzer 3
#define OUT_H_VoiceReset 1
#define OUT_H_HAPTIC 0
// Rotary encoders driver
#define INP_E_ROT_ENC_1_A 4
#define INP_E_ROT_ENC_1_B 5
#define INP_D_ROT_ENC_2_A 2
#define INP_D_ROT_ENC_2_B 3
#define INP_J_ROT_ENC_1_PUSH 0
#define INP_J_ROT_ENC_2_PUSH 1
#define REA_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_1_PUSH))
#define REB_DOWN() (~PINJ & (1<<INP_J_ROT_ENC_2_PUSH))
#define ROTENC_DOWN() (REA_DOWN() || REB_DOWN())
#define ROTENC_DIV2 // rotary encoders resolution/2
// LCD driver
#define PORTA_LCD_DAT PORTA
#define PORTC_LCD_CTRL PORTC
#if defined(LCD_KS108) // (For KS108 LCD only) MEGA R/W pin always at 0 state in Opentx then
#define OUT_C_LCD_CS2 6 // use this pin to control second KS108 (CS2)
#else // and connect KS108 R/W pin to ground via a 1k resistor
#define OUT_C_LCD_RnW 6
#endif
#define OUT_C_LCD_E 7
#define OUT_C_LCD_A0 5
#define OUT_C_LCD_RES 4
#define OUT_C_LCD_CS1 3
#define OUT_C_LIGHT 2
// DBLKeys driver
#define KEYS_PRESSED() (~PINL)
// Power driver
uint8_t pwrCheck();
void pwrOff();
#if defined(PWRMANAGE)
#define UNEXPECTED_SHUTDOWN() ((mcusr & (1 << WDRF)) || g_eeGeneral.unexpectedShutdown)
#else
#define UNEXPECTED_SHUTDOWN() (mcusr & (1 << WDRF))
#endif
// USB fake driver
#define usbPlugged() false
// Haptic driver
#define hapticOn() PORTH |= (1 << OUT_H_HAPTIC)
#define hapticOff() PORTH &= ~(1 << OUT_H_HAPTIC)
// Buzzer driver
#define buzzerOn() PORTH |= (1 << OUT_H_SpeakerBuzzer)
#define buzzerOff() PORTH &= ~(1 << OUT_H_SpeakerBuzzer)
// Speaker driver
#if defined(AUDIO)
#define speakerOn() TCCR4A |= (1 << COM4A0)
#define speakerOff() TCCR4A &= ~(1 << COM4A0)
#endif
// Voice driver (WTV20)
#if defined(VOICE_WTV20)
#define WTV20_Data_on PORTE |= (1<<OUT_E_VoiceData)
#define WTV20_Data_off PORTE &= ~(1<<OUT_E_VoiceData)
#define WTV20_BUSY (PINB & (1<<INP_B_VoiceBuzy))
#define WTV20_Clock_on PORTG |= (1<<OUT_G_VoiceClock)
#define WTV20_Clock_off PORTG &= ~(1<<OUT_G_VoiceClock)
#define WTV20_CLK (PING & (1<<OUT_G_VoiceClock))
#define WTV20_Reset_on PORTH |= (1<<OUT_H_VoiceReset)
#define WTV20_Reset_off PORTH &= ~(1<<OUT_H_VoiceReset)
#endif
// Voice driver (JQ6500)
#if defined(VOICE_JQ6500)
#define JQ6500_Serial_on PORTE |= (1<<OUT_E_VoiceData)
#define JQ6500_Serial_off PORTE &= ~(1<<OUT_E_VoiceData)
#define JQ6500_BUSY (PINB & (1<<INP_B_VoiceBuzy))
#endif
#endif // _BOARD_MEGA2560_H_

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,246 +1,246 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include <string.h>
#include "debug.h"
#include "diskio.h"
#include "board_lowlevel.h"
#include "Media.h"
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
/// Number of SD Slots
#define NUM_SD_SLOTS 1
//------------------------------------------------------------------------------
/// Checks if the device is write protected.
/// \return 1 if protected.
//------------------------------------------------------------------------------
#if 0
static unsigned char CardIsProtected(unsigned char slot)
{
if (slot == 0) {
#ifdef BOARD_SD_PIN_WP
PIO_Configure(&pinMciWriteProtect, 1);
return (PIO_Get(&pinMciWriteProtect) != 0);
#else
return 0;
#endif
}
if (slot == 1) {
#ifdef BOARD_SD_MCI1_PIN_WP
PIO_Configure(&pinMciWriteProtect1, 1);
return (PIO_Get(&pinMciWriteProtect1) != 0);
#else
return 0;
#endif
}
return 0;
}
#endif
//------------------------------------------------------------------------------
/// Configure the PIO for SD
//------------------------------------------------------------------------------
#if 0
static void ConfigurePIO(unsigned char mciID)
{
#ifdef BOARD_SD_PINS
const Pin pinSd0[] = {BOARD_SD_PINS};
#endif
#ifdef BOARD_SD_MCI1_PINS
const Pin pinSd1[] = {BOARD_SD_MCI1_PINS};
#endif
if(mciID == 0) {
#ifdef BOARD_SD_PINS
PIO_Configure(pinSd0, PIO_LISTSIZE(pinSd0));
#endif
} else {
#ifdef BOARD_SD_MCI1_PINS
PIO_Configure(pinSd1, PIO_LISTSIZE(pinSd1));
#endif
}
}
#endif
//------------------------------------------------------------------------------
//! \brief Reads a specified amount of data from a SDCARD memory
//! \param media Pointer to a Media instance
//! \param address Address of the data to read
//! \param data Pointer to the buffer in which to store the retrieved
//! data
//! \param length Length of the buffer
//! \param callback Optional pointer to a callback function to invoke when
//! the operation is finished
//! \param argument Optional pointer to an argument for the callback
//! \return Operation result code
//------------------------------------------------------------------------------
static unsigned char MEDSdcard_Read(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument)
{
TRACE_DEBUG("MEDSdcard_Read(address=%d length=%d)\n\r", address, length);
// Check that the media is ready
if (media->state != MED_STATE_READY) {
TRACE_INFO("Media busy\n\r");
return MED_STATUS_BUSY;
}
// Check that the data to read is not too big
if ((length + address) > media->size) {
TRACE_WARNING("MEDSdcard_Read: Data too big: %d, %d\n\r",
(int)length, (int)address);
return MED_STATUS_ERROR;
}
// Enter Busy state
media->state = MED_STATE_BUSY;
disk_read (0, data, address, length);
// Leave the Busy state
media->state = MED_STATE_READY;
// Invoke callback
if (callback != 0) {
callback(argument, MED_STATUS_SUCCESS, 0, 0);
}
return MED_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
//! \brief Writes data on a SDRAM media
//! \param media Pointer to a Media instance
//! \param address Address at which to write
//! \param data Pointer to the data to write
//! \param length Size of the data buffer
//! \param callback Optional pointer to a callback function to invoke when
//! the write operation terminates
//! \param argument Optional argument for the callback function
//! \return Operation result code
//! \see Media
//! \see MediaCallback
//------------------------------------------------------------------------------
static unsigned char MEDSdcard_Write(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument)
{
TRACE_DEBUG("MEDSdcard_Write(address=%d length=%d)\n\r", address, length);
// Check that the media if ready
if (media->state != MED_STATE_READY) {
TRACE_WARNING("MEDSdcard_Write: Media is busy\n\r");
return MED_STATUS_BUSY;
}
// Check that the data to write is not too big
if ((length + address) > media->size) {
TRACE_WARNING("MEDSdcard_Write: Data too big\n\r");
return MED_STATUS_ERROR;
}
// Put the media in Busy state
media->state = MED_STATE_BUSY;
disk_write(0, data, address, length);
// Leave the Busy state
media->state = MED_STATE_READY;
// Invoke the callback if it exists
if (callback != 0) {
callback(argument, MED_STATUS_SUCCESS, 0, 0);
}
return MED_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
/// Initializes a Media instance and the associated physical interface
/// \param media Pointer to the Media instance to initialize
/// \return 1 if success.
//------------------------------------------------------------------------------
unsigned char MEDSdcard_Initialize(Media *media, unsigned char mciID)
{
TRACE_INFO("MEDSdcard init\n\r");
// Initialize SDcard
//--------------------------------------------------------------------------
if ( !SD_CARD_PRESENT( ) )
{
return 0;
}
media->write = MEDSdcard_Write;
media->read = MEDSdcard_Read;
media->lock = 0;
media->unlock = 0;
media->handler = 0;
media->flush = 0;
media->blockSize = BLOCK_SIZE;
media->baseAddress = 0;
media->size = SD_GET_BLOCKNR();
media->mappedRD = 0;
media->mappedWR = 0;
media->protected = 0;
media->removable = 1;
media->state = MED_STATE_READY;
media->transfer.data = 0;
media->transfer.address = 0;
media->transfer.length = 0;
media->transfer.callback = 0;
media->transfer.argument = 0;
return 1;
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include <string.h>
#include "debug.h"
#include "diskio.h"
#include "board_lowlevel.h"
#include "Media.h"
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
/// Number of SD Slots
#define NUM_SD_SLOTS 1
//------------------------------------------------------------------------------
/// Checks if the device is write protected.
/// \return 1 if protected.
//------------------------------------------------------------------------------
#if 0
static unsigned char CardIsProtected(unsigned char slot)
{
if (slot == 0) {
#ifdef BOARD_SD_PIN_WP
PIO_Configure(&pinMciWriteProtect, 1);
return (PIO_Get(&pinMciWriteProtect) != 0);
#else
return 0;
#endif
}
if (slot == 1) {
#ifdef BOARD_SD_MCI1_PIN_WP
PIO_Configure(&pinMciWriteProtect1, 1);
return (PIO_Get(&pinMciWriteProtect1) != 0);
#else
return 0;
#endif
}
return 0;
}
#endif
//------------------------------------------------------------------------------
/// Configure the PIO for SD
//------------------------------------------------------------------------------
#if 0
static void ConfigurePIO(unsigned char mciID)
{
#ifdef BOARD_SD_PINS
const Pin pinSd0[] = {BOARD_SD_PINS};
#endif
#ifdef BOARD_SD_MCI1_PINS
const Pin pinSd1[] = {BOARD_SD_MCI1_PINS};
#endif
if(mciID == 0) {
#ifdef BOARD_SD_PINS
PIO_Configure(pinSd0, PIO_LISTSIZE(pinSd0));
#endif
} else {
#ifdef BOARD_SD_MCI1_PINS
PIO_Configure(pinSd1, PIO_LISTSIZE(pinSd1));
#endif
}
}
#endif
//------------------------------------------------------------------------------
//! \brief Reads a specified amount of data from a SDCARD memory
//! \param media Pointer to a Media instance
//! \param address Address of the data to read
//! \param data Pointer to the buffer in which to store the retrieved
//! data
//! \param length Length of the buffer
//! \param callback Optional pointer to a callback function to invoke when
//! the operation is finished
//! \param argument Optional pointer to an argument for the callback
//! \return Operation result code
//------------------------------------------------------------------------------
static unsigned char MEDSdcard_Read(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument)
{
TRACE_DEBUG("MEDSdcard_Read(address=%d length=%d)\n\r", address, length);
// Check that the media is ready
if (media->state != MED_STATE_READY) {
TRACE_INFO("Media busy\n\r");
return MED_STATUS_BUSY;
}
// Check that the data to read is not too big
if ((length + address) > media->size) {
TRACE_WARNING("MEDSdcard_Read: Data too big: %d, %d\n\r",
(int)length, (int)address);
return MED_STATUS_ERROR;
}
// Enter Busy state
media->state = MED_STATE_BUSY;
disk_read (0, data, address, length);
// Leave the Busy state
media->state = MED_STATE_READY;
// Invoke callback
if (callback != 0) {
callback(argument, MED_STATUS_SUCCESS, 0, 0);
}
return MED_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
//! \brief Writes data on a SDRAM media
//! \param media Pointer to a Media instance
//! \param address Address at which to write
//! \param data Pointer to the data to write
//! \param length Size of the data buffer
//! \param callback Optional pointer to a callback function to invoke when
//! the write operation terminates
//! \param argument Optional argument for the callback function
//! \return Operation result code
//! \see Media
//! \see MediaCallback
//------------------------------------------------------------------------------
static unsigned char MEDSdcard_Write(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument)
{
TRACE_DEBUG("MEDSdcard_Write(address=%d length=%d)\n\r", address, length);
// Check that the media if ready
if (media->state != MED_STATE_READY) {
TRACE_WARNING("MEDSdcard_Write: Media is busy\n\r");
return MED_STATUS_BUSY;
}
// Check that the data to write is not too big
if ((length + address) > media->size) {
TRACE_WARNING("MEDSdcard_Write: Data too big\n\r");
return MED_STATUS_ERROR;
}
// Put the media in Busy state
media->state = MED_STATE_BUSY;
disk_write(0, data, address, length);
// Leave the Busy state
media->state = MED_STATE_READY;
// Invoke the callback if it exists
if (callback != 0) {
callback(argument, MED_STATUS_SUCCESS, 0, 0);
}
return MED_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
/// Initializes a Media instance and the associated physical interface
/// \param media Pointer to the Media instance to initialize
/// \return 1 if success.
//------------------------------------------------------------------------------
unsigned char MEDSdcard_Initialize(Media *media, unsigned char mciID)
{
TRACE_INFO("MEDSdcard init\n\r");
// Initialize SDcard
//--------------------------------------------------------------------------
if ( !SD_CARD_PRESENT( ) )
{
return 0;
}
media->write = MEDSdcard_Write;
media->read = MEDSdcard_Read;
media->lock = 0;
media->unlock = 0;
media->handler = 0;
media->flush = 0;
media->blockSize = BLOCK_SIZE;
media->baseAddress = 0;
media->size = SD_GET_BLOCKNR();
media->mappedRD = 0;
media->mappedWR = 0;
media->protected = 0;
media->removable = 1;
media->state = MED_STATE_READY;
media->transfer.data = 0;
media->transfer.address = 0;
media->transfer.length = 0;
media->transfer.callback = 0;
media->transfer.argument = 0;
return 1;
}

View file

@ -18,262 +18,262 @@
* GNU General Public License for more details.
*/
//------------------------------------------------------------------------------
/// \unit
/// !Purpose
///
/// Generic Media type, which provides transparent access to all types of
/// memories.
///
/// \note The physical or HW related media operations (physical device
/// connection & protection detecting, PIO configurations and interface
/// driver initialization) are excluded.
///
/// !Usage
/// -# Do PIO initialization for peripheral interfaces.
/// -# Initialize peripheral interface driver & device driver.
/// -# Initialize specific media interface and link to this initialized driver.
///
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// \unit
/// !Purpose
///
/// Generic Media type, which provides transparent access to all types of
/// memories.
///
/// \note The physical or HW related media operations (physical device
/// connection & protection detecting, PIO configurations and interface
/// driver initialization) are excluded.
///
/// !Usage
/// -# Do PIO initialization for peripheral interfaces.
/// -# Initialize peripheral interface driver & device driver.
/// -# Initialize specific media interface and link to this initialized driver.
///
//------------------------------------------------------------------------------
#ifndef _MEDIA_H_
#define _MEDIA_H_
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
//! \brief Operation result code returned by media methods
#define MED_STATUS_SUCCESS 0x00
#define MED_STATUS_ERROR 0x01
#define MED_STATUS_BUSY 0x02
#define MED_STATUS_PROTECTED 0x04
//! \brief Media statuses
#define MED_STATE_READY 0x00 /// Media is ready for access
#define MED_STATE_BUSY 0x01 /// Media is busy
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
typedef struct _Media Media;
typedef void (*MediaCallback)(void *argument,
unsigned char status,
unsigned int transferred,
unsigned int remaining);
typedef unsigned char (*Media_write)(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument);
typedef unsigned char (*Media_read)(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument);
typedef unsigned char (*Media_cancelIo)(Media *media);
typedef unsigned char (*Media_lock)(Media *media,
unsigned int start,
unsigned int end,
unsigned int *pActualStart,
unsigned int *pActualEnd);
typedef unsigned char (*Media_unlock)(Media *media,
unsigned int start,
unsigned int end,
unsigned int *pActualStart,
unsigned int *pActualEnd);
typedef unsigned char (*Media_ioctl)(Media *media,
unsigned char ctrl,
void *buff);
typedef unsigned char (*Media_flush)(Media *media);
typedef void (*Media_handler)(Media *media);
//! \brief Media transfer
//! \see TransferCallback
typedef struct {
void *data; //!< Pointer to the data buffer
unsigned int address; //!< Address where to read/write the data
unsigned int length; //!< Size of the data to read/write
MediaCallback callback; //!< Callback to invoke when the transfer done
void *argument; //!< Callback argument
} MEDTransfer;
//! \brief Media object
//! \see MEDTransfer
struct _Media {
Media_write write; //!< Write method
Media_read read; //!< Read method
Media_cancelIo cancelIo; //!< Cancel pending IO method
Media_lock lock; //!< lock method if possible
Media_unlock unlock; //!< unlock method if possible
Media_flush flush; //!< Flush method
Media_handler handler; //!< Interrupt handler
unsigned int blockSize; //!< Block size in bytes (1, 512, 1K, 2K ...)
unsigned int baseAddress; //!< Base address of media in number of blocks
unsigned int size; //!< Size of media in number of blocks
MEDTransfer transfer; //!< Current transfer operation
void *interface; //!< Pointer to the physical interface used
unsigned char bReserved:4,
mappedRD:1, //!< Mapped to memory space to read
mappedWR:1, //!< Mapped to memory space to write
#ifdef __cplusplus
protectd:1, //!< Protected media?
#else
protected:1, //!< Protected media?
#endif
removable:1; //!< Removable/Fixed media?
unsigned char state; //!< Status of media
unsigned short reserved;
};
/// Available medias.
extern Media medias[];
/// Number of medias which are effectively used.
/// Defined by Media, shared usage by USB MSD & FS ...
extern unsigned int numMedias;
//------------------------------------------------------------------------------
// Inline Functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//! \brief Writes data on a media
//! \param media Pointer to a Media instance
//! \param address Address at which to write
//! \param data Pointer to the data to write
//! \param length Size of the data buffer
//! \param callback Optional pointer to a callback function to invoke when
//! the write operation terminates
//! \param argument Optional argument for the callback function
//! \return Operation result code
//! \see TransferCallback
//------------------------------------------------------------------------------
static inline unsigned char MED_Write(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument)
{
return media->write(media, address, data, length, callback, argument);
}
//------------------------------------------------------------------------------
//! \brief Reads a specified amount of data from a media
//! \param media Pointer to a Media instance
//! \param address Address of the data to read
//! \param data Pointer to the buffer in which to store the retrieved
//! data
//! \param length Length of the buffer
//! \param callback Optional pointer to a callback function to invoke when
//! the operation is finished
//! \param argument Optional pointer to an argument for the callback
//! \return Operation result code
//! \see TransferCallback
//------------------------------------------------------------------------------
static inline unsigned char MED_Read(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument)
{
return media->read(media, address, data, length, callback, argument);
}
//------------------------------------------------------------------------------
//! \brief Locks all the regions in the given address range.
//! \param media Pointer to a Media instance
/// \param start Start address of lock range.
/// \param end End address of lock range.
/// \param pActualStart Start address of the actual lock range (optional).
/// \param pActualEnd End address of the actual lock range (optional).
/// \return 0 if successful; otherwise returns an error code.
//------------------------------------------------------------------------------
static inline unsigned char MED_Lock(Media *media,
unsigned int start,
unsigned int end,
unsigned int *pActualStart,
unsigned int *pActualEnd)
{
if( media->lock ) {
return media->lock(media, start, end, pActualStart, pActualEnd);
}
else {
return MED_STATUS_SUCCESS;
}
}
//------------------------------------------------------------------------------
//! \brief Unlocks all the regions in the given address range
//! \param media Pointer to a Media instance
/// \param start Start address of unlock range.
/// \param end End address of unlock range.
/// \param pActualStart Start address of the actual unlock range (optional).
/// \param pActualEnd End address of the actual unlock range (optional).
/// \return 0 if successful; otherwise returns an error code.
//------------------------------------------------------------------------------
static inline unsigned char MED_Unlock(Media *media,
unsigned int start,
unsigned int end,
unsigned int *pActualStart,
unsigned int *pActualEnd)
{
if( media->unlock ) {
return media->unlock(media, start, end, pActualStart, pActualEnd);
}
else {
return MED_STATUS_SUCCESS;
}
}
//------------------------------------------------------------------------------
//! \brief
//! \param media Pointer to the Media instance to use
//------------------------------------------------------------------------------
static inline unsigned char MED_Flush(Media *media)
{
if (media->flush) {
return media->flush(media);
}
else {
return MED_STATUS_SUCCESS;
}
}
//------------------------------------------------------------------------------
//! \brief Invokes the interrupt handler of the specified media
//! \param media Pointer to the Media instance to use
//------------------------------------------------------------------------------
static inline void MED_Handler(Media *media)
{
if (media->handler) {
media->handler(media);
}
}
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
extern void MED_HandleAll(Media *medias, unsigned char numMedias);
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
//! \brief Operation result code returned by media methods
#define MED_STATUS_SUCCESS 0x00
#define MED_STATUS_ERROR 0x01
#define MED_STATUS_BUSY 0x02
#define MED_STATUS_PROTECTED 0x04
//! \brief Media statuses
#define MED_STATE_READY 0x00 /// Media is ready for access
#define MED_STATE_BUSY 0x01 /// Media is busy
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
typedef struct _Media Media;
typedef void (*MediaCallback)(void *argument,
unsigned char status,
unsigned int transferred,
unsigned int remaining);
typedef unsigned char (*Media_write)(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument);
typedef unsigned char (*Media_read)(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument);
typedef unsigned char (*Media_cancelIo)(Media *media);
typedef unsigned char (*Media_lock)(Media *media,
unsigned int start,
unsigned int end,
unsigned int *pActualStart,
unsigned int *pActualEnd);
typedef unsigned char (*Media_unlock)(Media *media,
unsigned int start,
unsigned int end,
unsigned int *pActualStart,
unsigned int *pActualEnd);
typedef unsigned char (*Media_ioctl)(Media *media,
unsigned char ctrl,
void *buff);
typedef unsigned char (*Media_flush)(Media *media);
typedef void (*Media_handler)(Media *media);
//! \brief Media transfer
//! \see TransferCallback
typedef struct {
void *data; //!< Pointer to the data buffer
unsigned int address; //!< Address where to read/write the data
unsigned int length; //!< Size of the data to read/write
MediaCallback callback; //!< Callback to invoke when the transfer done
void *argument; //!< Callback argument
} MEDTransfer;
//! \brief Media object
//! \see MEDTransfer
struct _Media {
Media_write write; //!< Write method
Media_read read; //!< Read method
Media_cancelIo cancelIo; //!< Cancel pending IO method
Media_lock lock; //!< lock method if possible
Media_unlock unlock; //!< unlock method if possible
Media_flush flush; //!< Flush method
Media_handler handler; //!< Interrupt handler
unsigned int blockSize; //!< Block size in bytes (1, 512, 1K, 2K ...)
unsigned int baseAddress; //!< Base address of media in number of blocks
unsigned int size; //!< Size of media in number of blocks
MEDTransfer transfer; //!< Current transfer operation
void *interface; //!< Pointer to the physical interface used
unsigned char bReserved:4,
mappedRD:1, //!< Mapped to memory space to read
mappedWR:1, //!< Mapped to memory space to write
#ifdef __cplusplus
protectd:1, //!< Protected media?
#else
protected:1, //!< Protected media?
#endif
removable:1; //!< Removable/Fixed media?
unsigned char state; //!< Status of media
unsigned short reserved;
};
/// Available medias.
extern Media medias[];
/// Number of medias which are effectively used.
/// Defined by Media, shared usage by USB MSD & FS ...
extern unsigned int numMedias;
//------------------------------------------------------------------------------
// Inline Functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//! \brief Writes data on a media
//! \param media Pointer to a Media instance
//! \param address Address at which to write
//! \param data Pointer to the data to write
//! \param length Size of the data buffer
//! \param callback Optional pointer to a callback function to invoke when
//! the write operation terminates
//! \param argument Optional argument for the callback function
//! \return Operation result code
//! \see TransferCallback
//------------------------------------------------------------------------------
static inline unsigned char MED_Write(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument)
{
return media->write(media, address, data, length, callback, argument);
}
//------------------------------------------------------------------------------
//! \brief Reads a specified amount of data from a media
//! \param media Pointer to a Media instance
//! \param address Address of the data to read
//! \param data Pointer to the buffer in which to store the retrieved
//! data
//! \param length Length of the buffer
//! \param callback Optional pointer to a callback function to invoke when
//! the operation is finished
//! \param argument Optional pointer to an argument for the callback
//! \return Operation result code
//! \see TransferCallback
//------------------------------------------------------------------------------
static inline unsigned char MED_Read(Media *media,
unsigned int address,
void *data,
unsigned int length,
MediaCallback callback,
void *argument)
{
return media->read(media, address, data, length, callback, argument);
}
//------------------------------------------------------------------------------
//! \brief Locks all the regions in the given address range.
//! \param media Pointer to a Media instance
/// \param start Start address of lock range.
/// \param end End address of lock range.
/// \param pActualStart Start address of the actual lock range (optional).
/// \param pActualEnd End address of the actual lock range (optional).
/// \return 0 if successful; otherwise returns an error code.
//------------------------------------------------------------------------------
static inline unsigned char MED_Lock(Media *media,
unsigned int start,
unsigned int end,
unsigned int *pActualStart,
unsigned int *pActualEnd)
{
if( media->lock ) {
return media->lock(media, start, end, pActualStart, pActualEnd);
}
else {
return MED_STATUS_SUCCESS;
}
}
//------------------------------------------------------------------------------
//! \brief Unlocks all the regions in the given address range
//! \param media Pointer to a Media instance
/// \param start Start address of unlock range.
/// \param end End address of unlock range.
/// \param pActualStart Start address of the actual unlock range (optional).
/// \param pActualEnd End address of the actual unlock range (optional).
/// \return 0 if successful; otherwise returns an error code.
//------------------------------------------------------------------------------
static inline unsigned char MED_Unlock(Media *media,
unsigned int start,
unsigned int end,
unsigned int *pActualStart,
unsigned int *pActualEnd)
{
if( media->unlock ) {
return media->unlock(media, start, end, pActualStart, pActualEnd);
}
else {
return MED_STATUS_SUCCESS;
}
}
//------------------------------------------------------------------------------
//! \brief
//! \param media Pointer to the Media instance to use
//------------------------------------------------------------------------------
static inline unsigned char MED_Flush(Media *media)
{
if (media->flush) {
return media->flush(media);
}
else {
return MED_STATUS_SUCCESS;
}
}
//------------------------------------------------------------------------------
//! \brief Invokes the interrupt handler of the specified media
//! \param media Pointer to the Media instance to use
//------------------------------------------------------------------------------
static inline void MED_Handler(Media *media)
{
if (media->handler) {
media->handler(media);
}
}
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
extern void MED_HandleAll(Media *medias, unsigned char numMedias);
#endif // _MEDIA_H_

View file

@ -1,148 +1,148 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint16_t adcValues[NUM_ANALOGS];
#if defined(FRSKY_STICKS)
const char ana_direction[NUM_ANALOGS] = {1, 1, 0, 1 ,0 ,1 ,0, 0, 0};
#endif
// Settings for mode register ADC_MR
// USEQ off - silicon problem, doesn't work
// TRANSFER = 3
// TRACKTIM = 15 (16 clock periods)
// ANACH = 1
// SETTLING = 6 (not used if ANACH = 0)
// STARTUP = 6 (96 clock periods)
// PRESCAL = 9.0 MHz clock (between 1 and 20MHz)
// FREERUN = 0
// FWUP = 0
// SLEEP = 0
// LOWRES = 0
// TRGSEL = 0
// TRGEN = 0 (software trigger only)
void adcInit()
{
Adc *padc ;
uint32_t timer ;
timer = ( Master_frequency / (3600000*2) ) << 8 ;
// Enable peripheral clock ADC = bit 29
PMC->PMC_PCER0 |= 0x20000000L ; // Enable peripheral clock to ADC
padc = ADC ;
padc->ADC_MR = 0x3FB60000 | timer ; // 0011 1111 1011 0110 xxxx xxxx 0000 0000
padc->ADC_ACR = ADC_ACR_TSON ; // Turn on temp sensor
#if defined(REVA)
padc->ADC_CHER = 0x0000E23E ; // channels 1,2,3,4,5,9,13,14,15
#else
padc->ADC_CHER = 0x0000E33E ; // channels 1,2,3,4,5,8,9,13,14,15
#endif
padc->ADC_CGR = 0 ; // Gain = 1, all channels
padc->ADC_COR = 0 ; // Single ended, 0 offset, all channels
}
// Read 8 (9 for REVB) ADC channels
// Documented bug, must do them 1 by 1
void adcSingleRead()
{
Adc *padc;
uint32_t y;
uint32_t x;
for (uint8_t i=0; i<4; i++)
padc = ADC;
y = padc->ADC_ISR; // Clear EOC flags
for (y = NUM_ANALOGS+1; --y > 0;) {
padc->ADC_CR = 2; // Start conversion
x = 0;
while ((padc->ADC_ISR & 0x01000000) == 0) {
// wait for DRDY flag
if (++x > 1000000) {
break; // Software timeout
}
}
x = padc->ADC_LCDR; // Clear DRSY flag
}
// Next bit may be done using the PDC
adcValues[0] = ADC->ADC_CDR1;
adcValues[1] = ADC->ADC_CDR2;
adcValues[2] = ADC->ADC_CDR3;
adcValues[3] = ADC->ADC_CDR4;
adcValues[4] = ADC->ADC_CDR5;
adcValues[5] = ADC->ADC_CDR9;
adcValues[6] = ADC->ADC_CDR13;
adcValues[7] = ADC->ADC_CDR14;
#if !defined(REVA)
adcValues[8] = ADC->ADC_CDR8 ;
#endif
temperature = (((int32_t)temperature * 7) + ((((int32_t)ADC->ADC_CDR15 - 838) * 621) >> 11)) >> 3; // Filter it
if (get_tmr10ms() >= 100 && temperature > maxTemperature) {
maxTemperature = temperature;
}
// adc direction correct
#if defined(FRSKY_STICKS)
uint32_t i ;
for (i=0; i<NUM_ANALOGS; i++) {
if (ana_direction[i]) {
adcValues[i] = 4096-adcValues[i];
}
}
#endif
}
void adcRead()
{
uint16_t temp[NUM_ANALOGS] = { 0 };
for (int i=0; i<4; i++) {
adcSingleRead();
for (uint8_t x=0; x<NUM_ANALOGS; x++) {
uint16_t val = adcValues[x];
#if defined(JITTER_MEASURE)
if (JITTER_MEASURE_ACTIVE()) {
rawJitter[x].measure(val);
}
#endif
temp[x] += val;
}
}
for (uint8_t x=0; x<NUM_ANALOGS; x++) {
adcValues[x] = temp[x] >> 2;
}
}
#if !defined(SIMU)
uint16_t getAnalogValue(uint8_t index)
{
#if defined(PCBSKY9X) && !defined(REVA)
static const uint8_t mapping[] = {1,5,7,0,4,6,2,3};
index = mapping[index];
#endif
return adcValues[index];
}
#endif // #if !defined(SIMU)
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint16_t adcValues[NUM_ANALOGS];
#if defined(FRSKY_STICKS)
const char ana_direction[NUM_ANALOGS] = {1, 1, 0, 1 ,0 ,1 ,0, 0, 0};
#endif
// Settings for mode register ADC_MR
// USEQ off - silicon problem, doesn't work
// TRANSFER = 3
// TRACKTIM = 15 (16 clock periods)
// ANACH = 1
// SETTLING = 6 (not used if ANACH = 0)
// STARTUP = 6 (96 clock periods)
// PRESCAL = 9.0 MHz clock (between 1 and 20MHz)
// FREERUN = 0
// FWUP = 0
// SLEEP = 0
// LOWRES = 0
// TRGSEL = 0
// TRGEN = 0 (software trigger only)
void adcInit()
{
Adc *padc ;
uint32_t timer ;
timer = ( Master_frequency / (3600000*2) ) << 8 ;
// Enable peripheral clock ADC = bit 29
PMC->PMC_PCER0 |= 0x20000000L ; // Enable peripheral clock to ADC
padc = ADC ;
padc->ADC_MR = 0x3FB60000 | timer ; // 0011 1111 1011 0110 xxxx xxxx 0000 0000
padc->ADC_ACR = ADC_ACR_TSON ; // Turn on temp sensor
#if defined(REVA)
padc->ADC_CHER = 0x0000E23E ; // channels 1,2,3,4,5,9,13,14,15
#else
padc->ADC_CHER = 0x0000E33E ; // channels 1,2,3,4,5,8,9,13,14,15
#endif
padc->ADC_CGR = 0 ; // Gain = 1, all channels
padc->ADC_COR = 0 ; // Single ended, 0 offset, all channels
}
// Read 8 (9 for REVB) ADC channels
// Documented bug, must do them 1 by 1
void adcSingleRead()
{
Adc *padc;
uint32_t y;
uint32_t x;
for (uint8_t i=0; i<4; i++)
padc = ADC;
y = padc->ADC_ISR; // Clear EOC flags
for (y = NUM_ANALOGS+1; --y > 0;) {
padc->ADC_CR = 2; // Start conversion
x = 0;
while ((padc->ADC_ISR & 0x01000000) == 0) {
// wait for DRDY flag
if (++x > 1000000) {
break; // Software timeout
}
}
x = padc->ADC_LCDR; // Clear DRSY flag
}
// Next bit may be done using the PDC
adcValues[0] = ADC->ADC_CDR1;
adcValues[1] = ADC->ADC_CDR2;
adcValues[2] = ADC->ADC_CDR3;
adcValues[3] = ADC->ADC_CDR4;
adcValues[4] = ADC->ADC_CDR5;
adcValues[5] = ADC->ADC_CDR9;
adcValues[6] = ADC->ADC_CDR13;
adcValues[7] = ADC->ADC_CDR14;
#if !defined(REVA)
adcValues[8] = ADC->ADC_CDR8 ;
#endif
temperature = (((int32_t)temperature * 7) + ((((int32_t)ADC->ADC_CDR15 - 838) * 621) >> 11)) >> 3; // Filter it
if (get_tmr10ms() >= 100 && temperature > maxTemperature) {
maxTemperature = temperature;
}
// adc direction correct
#if defined(FRSKY_STICKS)
uint32_t i ;
for (i=0; i<NUM_ANALOGS; i++) {
if (ana_direction[i]) {
adcValues[i] = 4096-adcValues[i];
}
}
#endif
}
void adcRead()
{
uint16_t temp[NUM_ANALOGS] = { 0 };
for (int i=0; i<4; i++) {
adcSingleRead();
for (uint8_t x=0; x<NUM_ANALOGS; x++) {
uint16_t val = adcValues[x];
#if defined(JITTER_MEASURE)
if (JITTER_MEASURE_ACTIVE()) {
rawJitter[x].measure(val);
}
#endif
temp[x] += val;
}
}
for (uint8_t x=0; x<NUM_ANALOGS; x++) {
adcValues[x] = temp[x] >> 2;
}
}
#if !defined(SIMU)
uint16_t getAnalogValue(uint8_t index)
{
#if defined(PCBSKY9X) && !defined(REVA)
static const uint8_t mapping[] = {1,5,7,0,4,6,2,3};
index = mapping[index];
#endif
return adcValues[index];
}
#endif // #if !defined(SIMU)

View file

@ -1,195 +1,195 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
volatile uint8_t dacStarted = false;
#if !defined(SIMU)
#if !defined(SOFTWARE_VOLUME)
const int8_t volumeScale[VOLUME_LEVEL_MAX+1] =
{
0, 2, 4, 6, 8, 10, 13, 17, 22, 27, 33, 40,
64, 82, 96, 105, 112, 117, 120, 122, 124, 125, 126, 127
} ;
#endif
void setSampleRate(uint32_t frequency)
{
Tc *ptc ;
uint32_t timer ;
timer = Master_frequency / (8 * frequency) ; // MCK/8 and 100 000 Hz
if (timer > 65535)
timer = 65535 ;
if (timer < 2)
timer = 2 ;
ptc = TC0 ; // Tc block 0 (TC0-2)
ptc->TC_CHANNEL[1].TC_CCR = TC_CCR0_CLKDIS ; // Stop clock
ptc->TC_CHANNEL[1].TC_RC = timer ; // 100 000 Hz
ptc->TC_CHANNEL[1].TC_RA = timer >> 1 ;
ptc->TC_CHANNEL[1].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
}
// Start TIMER1 at 100000Hz, used for DACC trigger
void dacTimerStart()
{
Tc *ptc ;
uint32_t timer ;
// Enable peripheral clock TC0 = bit 23 thru TC5 = bit 28
PMC->PMC_PCER0 |= 0x01000000L ; // Enable peripheral clock to TC1
timer = Master_frequency / 800000 ; // MCK/8 and 100 000 Hz
ptc = TC0 ; // Tc block 0 (TC0-2)
ptc->TC_BCR = 0 ; // No sync
ptc->TC_BMR = 0 ;
ptc->TC_CHANNEL[1].TC_CMR = 0x00008000 ; // Waveform mode
ptc->TC_CHANNEL[1].TC_RC = timer ; // 100 000 Hz
ptc->TC_CHANNEL[1].TC_RA = timer >> 1 ;
ptc->TC_CHANNEL[1].TC_CMR = 0x0009C001 ; // 0000 0000 0000 1001 1100 0000 0000 0001
// MCK/8, set @ RA, Clear @ RC waveform
ptc->TC_CHANNEL[1].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
// Sound_g.Frequency = 1000 ;
}
// Configure DAC0 (or DAC1 for REVA)
// Not sure why PB14 has not be allocated to the DAC, although it is an EXTRA function
// So maybe it is automatically done
void dacInit()
{
dacTimerStart() ;
PMC->PMC_PCER0 |= 0x40000000L ; // Enable peripheral clock to DAC
Dacc *dacptr = DACC;
#if defined(REVA)
dacptr->DACC_MR = 0x0B010215L ; // 0000 1011 0000 0001 0000 0010 0001 0101
dacptr->DACC_CHER = 2 ; // Enable channel 1
#else
dacptr->DACC_MR = 0x0B000215L ; // 0000 1011 0000 0001 0000 0010 0001 0101
dacptr->DACC_CHER = 1 ; // Enable channel 0
#endif
dacptr->DACC_CDR = 2048 ; // Half amplitude
dacptr->DACC_PTCR = DACC_PTCR_TXTEN ;
NVIC_EnableIRQ(DACC_IRQn) ;
}
inline void dacStart()
{
PMC->PMC_PCER0 |= 0x40000000L ; // Enable peripheral clock to DAC
DACC->DACC_IER = DACC_IER_ENDTX ;
dacStarted = true;
}
inline void dacStop()
{
DACC->DACC_IDR = DACC_IDR_ENDTX ; // Disable interrupt
dacStarted = false;
}
void audioConsumeCurrentBuffer()
{
if (!dacStarted) {
dacStart();
}
}
extern "C" void DAC_IRQHandler()
{
uint32_t sr = DACC->DACC_ISR;
if (sr & DACC_ISR_ENDTX) {
audioQueue.buffersFifo.freeNextFilledBuffer();
const AudioBuffer * nextBuffer = audioQueue.buffersFifo.getNextFilledBuffer();
if (nextBuffer) {
// Try the first PDC buffer
if ((DACC->DACC_TCR == 0) && (DACC->DACC_TNCR == 0)) {
DACC->DACC_TPR = CONVERT_PTR_UINT(nextBuffer->data);
DACC->DACC_TCR = nextBuffer->size/2;
DACC->DACC_PTCR = DACC_PTCR_TXTEN;
return;
}
// Try the second PDC buffer
if (DACC->DACC_TNCR == 0) {
DACC->DACC_TNPR = CONVERT_PTR_UINT(nextBuffer->data);
DACC->DACC_TNCR = nextBuffer->size/2;
DACC->DACC_PTCR = DACC_PTCR_TXTEN;
return;
}
}
else {
dacStop();
}
}
}
// Sound routines
void audioInit()
{
Pio * pioptr ;
dacInit() ;
pioptr = PIOA ;
#if defined(REVA)
pioptr->PIO_CODR = 0x00010000L ; // Set bit A16 OFF
pioptr->PIO_PER = 0x00010000L ; // Enable bit A16 (Stock buzzer)
pioptr->PIO_OER = 0x00010000L ; // Set bit A16 as output
#else
pioptr->PIO_CODR = 0x02000000L ; // Set bit A25 OFF
pioptr->PIO_PER = 0x02000000L ; // Enable bit A25 (Stock buzzer)
pioptr->PIO_OER = 0x02000000L ; // Set bit A25 as output
#endif
#if defined(REVX)
configure_pins( PIO_PC26, PIN_ENABLE | PIN_LOW | PIN_OUTPUT | PIN_PORTC | PIN_NO_PULLUP ) ;
PIOC->PIO_CODR = PIO_PC26 ;
#endif
}
void audioEnd()
{
DACC->DACC_IDR = DACC_IDR_ENDTX ;
DACC->DACC_IDR = DACC_IDR_TXBUFE ;
NVIC_DisableIRQ(DACC_IRQn) ;
TWI0->TWI_IDR = TWI_IDR_TXCOMP ;
NVIC_DisableIRQ(TWI0_IRQn) ;
PMC->PMC_PCER0 &= ~0x00080000L ; // Disable peripheral clock to TWI0
PMC->PMC_PCER0 &= ~0x40000000L ; // Disable peripheral clock to DAC
}
#if !defined(SOFTWARE_VOLUME)
void setScaledVolume(uint8_t volume)
{
volumeRequired = volumeScale[min<uint8_t>(volume, VOLUME_LEVEL_MAX)];
__disable_irq() ;
i2cCheck() ;
__enable_irq() ;
}
#endif
#endif // #if !defined(SIMU)
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
volatile uint8_t dacStarted = false;
#if !defined(SIMU)
#if !defined(SOFTWARE_VOLUME)
const int8_t volumeScale[VOLUME_LEVEL_MAX+1] =
{
0, 2, 4, 6, 8, 10, 13, 17, 22, 27, 33, 40,
64, 82, 96, 105, 112, 117, 120, 122, 124, 125, 126, 127
} ;
#endif
void setSampleRate(uint32_t frequency)
{
Tc *ptc ;
uint32_t timer ;
timer = Master_frequency / (8 * frequency) ; // MCK/8 and 100 000 Hz
if (timer > 65535)
timer = 65535 ;
if (timer < 2)
timer = 2 ;
ptc = TC0 ; // Tc block 0 (TC0-2)
ptc->TC_CHANNEL[1].TC_CCR = TC_CCR0_CLKDIS ; // Stop clock
ptc->TC_CHANNEL[1].TC_RC = timer ; // 100 000 Hz
ptc->TC_CHANNEL[1].TC_RA = timer >> 1 ;
ptc->TC_CHANNEL[1].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
}
// Start TIMER1 at 100000Hz, used for DACC trigger
void dacTimerStart()
{
Tc *ptc ;
uint32_t timer ;
// Enable peripheral clock TC0 = bit 23 thru TC5 = bit 28
PMC->PMC_PCER0 |= 0x01000000L ; // Enable peripheral clock to TC1
timer = Master_frequency / 800000 ; // MCK/8 and 100 000 Hz
ptc = TC0 ; // Tc block 0 (TC0-2)
ptc->TC_BCR = 0 ; // No sync
ptc->TC_BMR = 0 ;
ptc->TC_CHANNEL[1].TC_CMR = 0x00008000 ; // Waveform mode
ptc->TC_CHANNEL[1].TC_RC = timer ; // 100 000 Hz
ptc->TC_CHANNEL[1].TC_RA = timer >> 1 ;
ptc->TC_CHANNEL[1].TC_CMR = 0x0009C001 ; // 0000 0000 0000 1001 1100 0000 0000 0001
// MCK/8, set @ RA, Clear @ RC waveform
ptc->TC_CHANNEL[1].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
// Sound_g.Frequency = 1000 ;
}
// Configure DAC0 (or DAC1 for REVA)
// Not sure why PB14 has not be allocated to the DAC, although it is an EXTRA function
// So maybe it is automatically done
void dacInit()
{
dacTimerStart() ;
PMC->PMC_PCER0 |= 0x40000000L ; // Enable peripheral clock to DAC
Dacc *dacptr = DACC;
#if defined(REVA)
dacptr->DACC_MR = 0x0B010215L ; // 0000 1011 0000 0001 0000 0010 0001 0101
dacptr->DACC_CHER = 2 ; // Enable channel 1
#else
dacptr->DACC_MR = 0x0B000215L ; // 0000 1011 0000 0001 0000 0010 0001 0101
dacptr->DACC_CHER = 1 ; // Enable channel 0
#endif
dacptr->DACC_CDR = 2048 ; // Half amplitude
dacptr->DACC_PTCR = DACC_PTCR_TXTEN ;
NVIC_EnableIRQ(DACC_IRQn) ;
}
inline void dacStart()
{
PMC->PMC_PCER0 |= 0x40000000L ; // Enable peripheral clock to DAC
DACC->DACC_IER = DACC_IER_ENDTX ;
dacStarted = true;
}
inline void dacStop()
{
DACC->DACC_IDR = DACC_IDR_ENDTX ; // Disable interrupt
dacStarted = false;
}
void audioConsumeCurrentBuffer()
{
if (!dacStarted) {
dacStart();
}
}
extern "C" void DAC_IRQHandler()
{
uint32_t sr = DACC->DACC_ISR;
if (sr & DACC_ISR_ENDTX) {
audioQueue.buffersFifo.freeNextFilledBuffer();
const AudioBuffer * nextBuffer = audioQueue.buffersFifo.getNextFilledBuffer();
if (nextBuffer) {
// Try the first PDC buffer
if ((DACC->DACC_TCR == 0) && (DACC->DACC_TNCR == 0)) {
DACC->DACC_TPR = CONVERT_PTR_UINT(nextBuffer->data);
DACC->DACC_TCR = nextBuffer->size/2;
DACC->DACC_PTCR = DACC_PTCR_TXTEN;
return;
}
// Try the second PDC buffer
if (DACC->DACC_TNCR == 0) {
DACC->DACC_TNPR = CONVERT_PTR_UINT(nextBuffer->data);
DACC->DACC_TNCR = nextBuffer->size/2;
DACC->DACC_PTCR = DACC_PTCR_TXTEN;
return;
}
}
else {
dacStop();
}
}
}
// Sound routines
void audioInit()
{
Pio * pioptr ;
dacInit() ;
pioptr = PIOA ;
#if defined(REVA)
pioptr->PIO_CODR = 0x00010000L ; // Set bit A16 OFF
pioptr->PIO_PER = 0x00010000L ; // Enable bit A16 (Stock buzzer)
pioptr->PIO_OER = 0x00010000L ; // Set bit A16 as output
#else
pioptr->PIO_CODR = 0x02000000L ; // Set bit A25 OFF
pioptr->PIO_PER = 0x02000000L ; // Enable bit A25 (Stock buzzer)
pioptr->PIO_OER = 0x02000000L ; // Set bit A25 as output
#endif
#if defined(REVX)
configure_pins( PIO_PC26, PIN_ENABLE | PIN_LOW | PIN_OUTPUT | PIN_PORTC | PIN_NO_PULLUP ) ;
PIOC->PIO_CODR = PIO_PC26 ;
#endif
}
void audioEnd()
{
DACC->DACC_IDR = DACC_IDR_ENDTX ;
DACC->DACC_IDR = DACC_IDR_TXBUFE ;
NVIC_DisableIRQ(DACC_IRQn) ;
TWI0->TWI_IDR = TWI_IDR_TXCOMP ;
NVIC_DisableIRQ(TWI0_IRQn) ;
PMC->PMC_PCER0 &= ~0x00080000L ; // Disable peripheral clock to TWI0
PMC->PMC_PCER0 &= ~0x40000000L ; // Disable peripheral clock to DAC
}
#if !defined(SOFTWARE_VOLUME)
void setScaledVolume(uint8_t volume)
{
volumeRequired = volumeScale[min<uint8_t>(volume, VOLUME_LEVEL_MAX)];
__disable_irq() ;
i2cCheck() ;
__enable_irq() ;
}
#endif
#endif // #if !defined(SIMU)

File diff suppressed because it is too large Load diff

View file

@ -1,414 +1,414 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BOARD_SKY9X_H_
#define _BOARD_SKY9X_H_
#include <stdio.h>
#include "board_lowlevel.h"
#include "audio_driver.h"
extern uint16_t ResetReason;
#define BOOTLOADER_SIZE 0x8000
#define FIRMWARE_SIZE (256*1024)
#define FIRMWARE_ADDRESS 0x00400000
// Board driver
void boardInit(void);
#define boardOff() pwrOff()
// Rotary Encoder driver
void rotencInit();
void rotencEnd();
#if !defined(REVX) && !defined(AR9X)
#define ROTARY_ENCODERS 1
#define ROTARY_ENCODER_NAVIGATION
#define REA_DOWN() (!(PIOB->PIO_PDSR & 0x40))
#else
#define REA_DOWN() (0)
#endif
// Keys driver
#define NUM_SWITCHES 7
enum EnumKeys
{
KEY_MENU,
KEY_ENTER=KEY_MENU,
KEY_EXIT,
KEY_DOWN,
KEY_MINUS = KEY_DOWN,
KEY_UP,
KEY_PLUS = KEY_UP,
KEY_RIGHT,
KEY_LEFT,
TRM_BASE,
TRM_LH_DWN = TRM_BASE,
TRM_LH_UP,
TRM_LV_DWN,
TRM_LV_UP,
TRM_RV_DWN,
TRM_RV_UP,
TRM_RH_DWN,
TRM_RH_UP,
TRM_LAST = TRM_RH_UP,
#if defined(ROTARY_ENCODERS)
BTN_REa,
#endif
NUM_KEYS
};
enum EnumSwitches
{
SW_ID0,
SW_ID1,
SW_ID2,
SW_THR,
SW_RUD,
SW_ELE,
SW_AIL,
SW_GEA,
SW_TRN,
};
#define IS_3POS(sw) ((sw) == 0)
#define IS_TOGGLE(sw) ((sw) == SWSRC_TRN)
#if defined(REVA)
#define KEYS_GPIO_REG_MENU PIOB->PIO_PDSR
#define KEYS_GPIO_REG_EXIT PIOA->PIO_PDSR
#define KEYS_GPIO_REG_UP PIOC->PIO_PDSR
#define KEYS_GPIO_REG_DOWN PIOC->PIO_PDSR
#define KEYS_GPIO_REG_RIGHT PIOC->PIO_PDSR
#define KEYS_GPIO_REG_LEFT PIOC->PIO_PDSR
#define KEYS_GPIO_PIN_MENU 0x00000040
#define KEYS_GPIO_PIN_EXIT 0x80000000
#define KEYS_GPIO_PIN_UP 0x00000004
#define KEYS_GPIO_PIN_DOWN 0x00000008
#define KEYS_GPIO_PIN_RIGHT 0x00000010
#define KEYS_GPIO_PIN_LEFT 0x00000020
#else
#define KEYS_GPIO_REG_MENU PIOB->PIO_PDSR
#define KEYS_GPIO_REG_EXIT PIOC->PIO_PDSR
#define KEYS_GPIO_REG_UP PIOC->PIO_PDSR
#define KEYS_GPIO_REG_DOWN PIOC->PIO_PDSR
#define KEYS_GPIO_REG_RIGHT PIOC->PIO_PDSR
#define KEYS_GPIO_REG_LEFT PIOC->PIO_PDSR
#define KEYS_GPIO_PIN_MENU 0x00000020
#define KEYS_GPIO_PIN_EXIT 0x01000000
#define KEYS_GPIO_PIN_UP 0x00000002
#define KEYS_GPIO_PIN_DOWN 0x00000020
#define KEYS_GPIO_PIN_RIGHT 0x00000010
#define KEYS_GPIO_PIN_LEFT 0x00000008
#endif
#if defined(REVX)
#define TRIMS_GPIO_REG_LHL PIOB->PIO_PDSR
#define TRIMS_GPIO_REG_LVD PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_RVU PIOC->PIO_PDSR
#define TRIMS_GPIO_REG_RHL PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_LHR PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_LVU PIOC->PIO_PDSR
#define TRIMS_GPIO_REG_RVD PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_RHR PIOC->PIO_PDSR
#else
#define TRIMS_GPIO_REG_LHL PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_LVD PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_RVU PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_RHL PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_LHR PIOB->PIO_PDSR
#define TRIMS_GPIO_REG_LVU PIOC->PIO_PDSR
#define TRIMS_GPIO_REG_RVD PIOC->PIO_PDSR
#define TRIMS_GPIO_REG_RHR PIOC->PIO_PDSR
#endif
#if defined(REVX)
#define TRIMS_GPIO_PIN_LHL 0x00000010
#define TRIMS_GPIO_PIN_LVD 0x01000000
#define TRIMS_GPIO_PIN_RVU 0x00000400
#define TRIMS_GPIO_PIN_RHL 0x00000001
#define TRIMS_GPIO_PIN_LHR 0x00800000
#define TRIMS_GPIO_PIN_LVU 0x10000000
#define TRIMS_GPIO_PIN_RVD 0x00000002
#define TRIMS_GPIO_PIN_RHR 0x00000200
#elif defined(REVA)
#define TRIMS_GPIO_PIN_LHL 0x00000080
#define TRIMS_GPIO_PIN_LVD 0x08000000
#define TRIMS_GPIO_PIN_RVU 0x40000000
#define TRIMS_GPIO_PIN_RHL 0x20000000
#define TRIMS_GPIO_PIN_LHR 0x00000010
#define TRIMS_GPIO_PIN_LVU 0x10000000
#define TRIMS_GPIO_PIN_RVD 0x00000400
#define TRIMS_GPIO_PIN_RHR 0x00000200
#else
#define TRIMS_GPIO_PIN_LHL 0x00800000
#define TRIMS_GPIO_PIN_LVD 0x01000000
#define TRIMS_GPIO_PIN_RVU 0x00000002
#define TRIMS_GPIO_PIN_RHL 0x00000001
#define TRIMS_GPIO_PIN_LHR 0x00000010
#define TRIMS_GPIO_PIN_LVU 0x10000000
#define TRIMS_GPIO_PIN_RVD 0x00000400
#define TRIMS_GPIO_PIN_RHR 0x00000200
#endif
// LCD driver
#define LCD_W 128
#define LCD_H 64
#define LCD_DEPTH 1
#define LCD_CONTRAST_MIN 10
#define LCD_CONTRAST_MAX 45
#define LCD_CONTRAST_DEFAULT 25
void lcdInit(void);
void lcdRefresh(void);
#define lcdRefreshWait()
void lcdSetRefVolt(uint8_t val);
void lcdSetContrast(void);
// USB driver
void usbMassStorage();
#define PIN_ENABLE 0x001
#define PIN_PERIPHERAL 0x000
#define PIN_INPUT 0x002
#define PIN_OUTPUT 0x000
#define PIN_PULLUP 0x004
#define PIN_NO_PULLUP 0x000
#define PIN_PULLDOWN 0x008
#define PIN_NO_PULLDOWN 0x000
#define PIN_PERI_MASK_L 0x010
#define PIN_PERI_MASK_H 0x020
#define PIN_PER_A 0x000
#define PIN_PER_B 0x010
#define PIN_PER_C 0x020
#define PIN_PER_D 0x030
#define PIN_PORT_MASK 0x0C0
#define PIN_PORTA 0x000
#define PIN_PORTB 0x040
#define PIN_PORTC 0x080
#define PIN_LOW 0x000
#define PIN_HIGH 0x100
// Telemetry port
#define SECOND_USART USART0
#define SECOND_ID ID_USART0
#define SECOND_PINS { PINS_USART0 }
void configure_pins( uint32_t pins, uint16_t config );
uint16_t getCurrent();
extern uint8_t temperature ; // Raw temp reading
extern uint8_t maxTemperature ; // Raw temp reading
uint8_t getTemperature();
#define strcpy_P strcpy
#define strcat_P strcat
#if !defined(REVA)
extern uint16_t Current_analogue;
extern uint16_t Current_max;
extern uint32_t Current_accumulator;
extern uint32_t Current_used;
extern uint16_t sessionTimer;
void calcConsumption();
#endif
// Trainer driver
#define SLAVE_MODE() (pwrCheck() == e_power_trainer)
#define TRAINER_CONNECTED() (PIOA->PIO_PDSR & PIO_PA8)
void checkTrainerSettings();
void init_trainer_capture();
// Write Flash driver
#define FLASH_PAGESIZE 256
void flashWrite(uint32_t * address, uint32_t * buffer);
// Keys driver
uint8_t keyState(uint8_t index);
uint32_t switchState(uint8_t index);
uint32_t readKeys(void);
uint32_t readTrims(void);
#define TRIMS_PRESSED() readTrims()
#define KEYS_PRESSED() readKeys()
// Pulses driver
void init_no_pulses(uint32_t port);
void disable_no_pulses(uint32_t port);
void init_ppm(uint32_t port);
void disable_ppm(uint32_t port);
void init_pxx(uint32_t port);
void disable_pxx(uint32_t port);
void init_dsm2(uint32_t port);
void disable_dsm2(uint32_t port);
#if defined(MULTIMODULE)
void init_multimodule(uint32_t module_index);
void disable_multimodule(uint32_t module_index);
#endif
// SD driver
#if defined(SIMU)
#define sdInit()
#define sdDone()
#else
#define sdPoll10ms()
#if defined(__cplusplus)
extern "C" {
#endif
void init_SDcard();
void sdInit();
void sdDone();
uint32_t sd_card_ready();
uint32_t sdMounted();
#if defined(__cplusplus)
}
#endif
#endif
// WDT driver
#if defined(WATCHDOG_DISABLED) || defined(SIMU)
#define wdt_disable()
#define wdt_enable(x)
#define wdt_reset()
#else
#define wdt_disable()
#define wdt_enable(x) WDT->WDT_MR = 0x3FFF207F
#define wdt_reset() WDT->WDT_CR = 0xA5000001
#endif
// Backlight driver
#define backlightEnable() (PWM->PWM_CH_NUM[0].PWM_CDTY = g_eeGeneral.backlightBright)
#define backlightDisable() (PWM->PWM_CH_NUM[0].PWM_CDTY = 100)
#define isBacklightEnabled() (PWM->PWM_CH_NUM[0].PWM_CDTY != 100)
#define BACKLIGHT_ENABLE() backlightEnable()
#define BACKLIGHT_DISABLE() backlightDisable()
// ADC driver
#define NUM_POTS 3
#define NUM_SLIDERS 0
#define NUM_XPOTS 0
enum Analogs {
STICK1,
STICK2,
STICK3,
STICK4,
POT_FIRST,
POT1 = POT_FIRST,
POT2,
POT3,
POT_LAST = POT3,
TX_VOLTAGE,
#if !defined(REVA)
TX_CURRENT,
#endif
NUM_ANALOGS
};
enum CalibratedAnalogs {
CALIBRATED_STICK1,
CALIBRATED_STICK2,
CALIBRATED_STICK3,
CALIBRATED_STICK4,
CALIBRATED_POT_FIRST,
CALIBRATED_POT1 = CALIBRATED_POT_FIRST,
CALIBRATED_POT2,
CALIBRATED_POT3,
CALIBRATED_POT_LAST = CALIBRATED_POT3,
NUM_CALIBRATED_ANALOGS
};
#define IS_POT(x) ((x)>=POT_FIRST && (x)<=POT_LAST)
#define IS_SLIDER(x) false
void adcInit();
void adcRead(void);
uint16_t getAnalogValue(uint8_t index);
uint16_t getBatteryVoltage(); // returns current battery voltage in 10mV steps
void setSticksGain(uint8_t gains);
// Buzzer driver
void buzzerSound(uint8_t duration);
void buzzerHeartbeat();
#define BUZZER_HEARTBEAT buzzerHeartbeat
// i2c driver
void i2cCheck();
// Coproc driver
void coprocInit();
void coprocWriteData(uint8_t *data, uint32_t size);
#if defined(__cplusplus)
void coprocReadData(bool onlytemp=false);
#endif
extern int8_t volumeRequired;
extern uint8_t Coproc_read;
extern int8_t Coproc_valid;
extern int8_t Coproc_temp;
extern int8_t Coproc_maxtemp;
// Haptic driver
void hapticOff(void);
void hapticOn(uint32_t pwmPercent);
// BlueTooth driver
#if defined(BLUETOOTH)
void btInit();
void btTask(void* pdata);
void btPushByte(uint8_t data);
#endif
// Power driver
#define TRAINER_PWR
#if !defined(REVA)
#define SOFT_PWR_CTRL
#endif
void pwrInit();
void pwrOff();
uint32_t pwrCheck();
uint32_t pwrPressed();
#define UNEXPECTED_SHUTDOWN() (g_eeGeneral.unexpectedShutdown)
// EEPROM driver
#define EEPROM_SIZE (4*1024*1024/8)
#define EEPROM_BLOCK_SIZE (4*1024)
void eepromInit();
uint8_t eepromReadStatus();
uint8_t eepromIsTransferComplete(void);
void eepromBlockErase(uint32_t address);
void eepromStartRead(uint8_t * buffer, size_t address, size_t size);
void eepromStartWrite(uint8_t * buffer, size_t address, size_t size);
// Debug driver
void debugPutc(const char c);
// Telemetry driver
void telemetryPortInit(uint32_t baudrate, uint8_t mode);
uint32_t telemetryTransmitPending();
void telemetryTransmitBuffer(uint8_t * buffer, uint32_t size);
void rxPdcUsart( void (*pChProcess)(uint8_t x) );
// Second UART driver
void serial2TelemetryInit(unsigned int protocol);
#if defined(__cplusplus)
bool telemetrySecondPortReceive(uint8_t & data);
#endif
extern const uint8_t BootCode[];
#endif // _BOARD_SKY9X_H_
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _BOARD_SKY9X_H_
#define _BOARD_SKY9X_H_
#include <stdio.h>
#include "board_lowlevel.h"
#include "audio_driver.h"
extern uint16_t ResetReason;
#define BOOTLOADER_SIZE 0x8000
#define FIRMWARE_SIZE (256*1024)
#define FIRMWARE_ADDRESS 0x00400000
// Board driver
void boardInit(void);
#define boardOff() pwrOff()
// Rotary Encoder driver
void rotencInit();
void rotencEnd();
#if !defined(REVX) && !defined(AR9X)
#define ROTARY_ENCODERS 1
#define ROTARY_ENCODER_NAVIGATION
#define REA_DOWN() (!(PIOB->PIO_PDSR & 0x40))
#else
#define REA_DOWN() (0)
#endif
// Keys driver
#define NUM_SWITCHES 7
enum EnumKeys
{
KEY_MENU,
KEY_ENTER=KEY_MENU,
KEY_EXIT,
KEY_DOWN,
KEY_MINUS = KEY_DOWN,
KEY_UP,
KEY_PLUS = KEY_UP,
KEY_RIGHT,
KEY_LEFT,
TRM_BASE,
TRM_LH_DWN = TRM_BASE,
TRM_LH_UP,
TRM_LV_DWN,
TRM_LV_UP,
TRM_RV_DWN,
TRM_RV_UP,
TRM_RH_DWN,
TRM_RH_UP,
TRM_LAST = TRM_RH_UP,
#if defined(ROTARY_ENCODERS)
BTN_REa,
#endif
NUM_KEYS
};
enum EnumSwitches
{
SW_ID0,
SW_ID1,
SW_ID2,
SW_THR,
SW_RUD,
SW_ELE,
SW_AIL,
SW_GEA,
SW_TRN,
};
#define IS_3POS(sw) ((sw) == 0)
#define IS_TOGGLE(sw) ((sw) == SWSRC_TRN)
#if defined(REVA)
#define KEYS_GPIO_REG_MENU PIOB->PIO_PDSR
#define KEYS_GPIO_REG_EXIT PIOA->PIO_PDSR
#define KEYS_GPIO_REG_UP PIOC->PIO_PDSR
#define KEYS_GPIO_REG_DOWN PIOC->PIO_PDSR
#define KEYS_GPIO_REG_RIGHT PIOC->PIO_PDSR
#define KEYS_GPIO_REG_LEFT PIOC->PIO_PDSR
#define KEYS_GPIO_PIN_MENU 0x00000040
#define KEYS_GPIO_PIN_EXIT 0x80000000
#define KEYS_GPIO_PIN_UP 0x00000004
#define KEYS_GPIO_PIN_DOWN 0x00000008
#define KEYS_GPIO_PIN_RIGHT 0x00000010
#define KEYS_GPIO_PIN_LEFT 0x00000020
#else
#define KEYS_GPIO_REG_MENU PIOB->PIO_PDSR
#define KEYS_GPIO_REG_EXIT PIOC->PIO_PDSR
#define KEYS_GPIO_REG_UP PIOC->PIO_PDSR
#define KEYS_GPIO_REG_DOWN PIOC->PIO_PDSR
#define KEYS_GPIO_REG_RIGHT PIOC->PIO_PDSR
#define KEYS_GPIO_REG_LEFT PIOC->PIO_PDSR
#define KEYS_GPIO_PIN_MENU 0x00000020
#define KEYS_GPIO_PIN_EXIT 0x01000000
#define KEYS_GPIO_PIN_UP 0x00000002
#define KEYS_GPIO_PIN_DOWN 0x00000020
#define KEYS_GPIO_PIN_RIGHT 0x00000010
#define KEYS_GPIO_PIN_LEFT 0x00000008
#endif
#if defined(REVX)
#define TRIMS_GPIO_REG_LHL PIOB->PIO_PDSR
#define TRIMS_GPIO_REG_LVD PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_RVU PIOC->PIO_PDSR
#define TRIMS_GPIO_REG_RHL PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_LHR PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_LVU PIOC->PIO_PDSR
#define TRIMS_GPIO_REG_RVD PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_RHR PIOC->PIO_PDSR
#else
#define TRIMS_GPIO_REG_LHL PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_LVD PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_RVU PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_RHL PIOA->PIO_PDSR
#define TRIMS_GPIO_REG_LHR PIOB->PIO_PDSR
#define TRIMS_GPIO_REG_LVU PIOC->PIO_PDSR
#define TRIMS_GPIO_REG_RVD PIOC->PIO_PDSR
#define TRIMS_GPIO_REG_RHR PIOC->PIO_PDSR
#endif
#if defined(REVX)
#define TRIMS_GPIO_PIN_LHL 0x00000010
#define TRIMS_GPIO_PIN_LVD 0x01000000
#define TRIMS_GPIO_PIN_RVU 0x00000400
#define TRIMS_GPIO_PIN_RHL 0x00000001
#define TRIMS_GPIO_PIN_LHR 0x00800000
#define TRIMS_GPIO_PIN_LVU 0x10000000
#define TRIMS_GPIO_PIN_RVD 0x00000002
#define TRIMS_GPIO_PIN_RHR 0x00000200
#elif defined(REVA)
#define TRIMS_GPIO_PIN_LHL 0x00000080
#define TRIMS_GPIO_PIN_LVD 0x08000000
#define TRIMS_GPIO_PIN_RVU 0x40000000
#define TRIMS_GPIO_PIN_RHL 0x20000000
#define TRIMS_GPIO_PIN_LHR 0x00000010
#define TRIMS_GPIO_PIN_LVU 0x10000000
#define TRIMS_GPIO_PIN_RVD 0x00000400
#define TRIMS_GPIO_PIN_RHR 0x00000200
#else
#define TRIMS_GPIO_PIN_LHL 0x00800000
#define TRIMS_GPIO_PIN_LVD 0x01000000
#define TRIMS_GPIO_PIN_RVU 0x00000002
#define TRIMS_GPIO_PIN_RHL 0x00000001
#define TRIMS_GPIO_PIN_LHR 0x00000010
#define TRIMS_GPIO_PIN_LVU 0x10000000
#define TRIMS_GPIO_PIN_RVD 0x00000400
#define TRIMS_GPIO_PIN_RHR 0x00000200
#endif
// LCD driver
#define LCD_W 128
#define LCD_H 64
#define LCD_DEPTH 1
#define LCD_CONTRAST_MIN 10
#define LCD_CONTRAST_MAX 45
#define LCD_CONTRAST_DEFAULT 25
void lcdInit(void);
void lcdRefresh(void);
#define lcdRefreshWait()
void lcdSetRefVolt(uint8_t val);
void lcdSetContrast(void);
// USB driver
void usbMassStorage();
#define PIN_ENABLE 0x001
#define PIN_PERIPHERAL 0x000
#define PIN_INPUT 0x002
#define PIN_OUTPUT 0x000
#define PIN_PULLUP 0x004
#define PIN_NO_PULLUP 0x000
#define PIN_PULLDOWN 0x008
#define PIN_NO_PULLDOWN 0x000
#define PIN_PERI_MASK_L 0x010
#define PIN_PERI_MASK_H 0x020
#define PIN_PER_A 0x000
#define PIN_PER_B 0x010
#define PIN_PER_C 0x020
#define PIN_PER_D 0x030
#define PIN_PORT_MASK 0x0C0
#define PIN_PORTA 0x000
#define PIN_PORTB 0x040
#define PIN_PORTC 0x080
#define PIN_LOW 0x000
#define PIN_HIGH 0x100
// Telemetry port
#define SECOND_USART USART0
#define SECOND_ID ID_USART0
#define SECOND_PINS { PINS_USART0 }
void configure_pins( uint32_t pins, uint16_t config );
uint16_t getCurrent();
extern uint8_t temperature ; // Raw temp reading
extern uint8_t maxTemperature ; // Raw temp reading
uint8_t getTemperature();
#define strcpy_P strcpy
#define strcat_P strcat
#if !defined(REVA)
extern uint16_t Current_analogue;
extern uint16_t Current_max;
extern uint32_t Current_accumulator;
extern uint32_t Current_used;
extern uint16_t sessionTimer;
void calcConsumption();
#endif
// Trainer driver
#define SLAVE_MODE() (pwrCheck() == e_power_trainer)
#define TRAINER_CONNECTED() (PIOA->PIO_PDSR & PIO_PA8)
void checkTrainerSettings();
void init_trainer_capture();
// Write Flash driver
#define FLASH_PAGESIZE 256
void flashWrite(uint32_t * address, uint32_t * buffer);
// Keys driver
uint8_t keyState(uint8_t index);
uint32_t switchState(uint8_t index);
uint32_t readKeys(void);
uint32_t readTrims(void);
#define TRIMS_PRESSED() readTrims()
#define KEYS_PRESSED() readKeys()
// Pulses driver
void init_no_pulses(uint32_t port);
void disable_no_pulses(uint32_t port);
void init_ppm(uint32_t port);
void disable_ppm(uint32_t port);
void init_pxx(uint32_t port);
void disable_pxx(uint32_t port);
void init_dsm2(uint32_t port);
void disable_dsm2(uint32_t port);
#if defined(MULTIMODULE)
void init_multimodule(uint32_t module_index);
void disable_multimodule(uint32_t module_index);
#endif
// SD driver
#if defined(SIMU)
#define sdInit()
#define sdDone()
#else
#define sdPoll10ms()
#if defined(__cplusplus)
extern "C" {
#endif
void init_SDcard();
void sdInit();
void sdDone();
uint32_t sd_card_ready();
uint32_t sdMounted();
#if defined(__cplusplus)
}
#endif
#endif
// WDT driver
#if defined(WATCHDOG_DISABLED) || defined(SIMU)
#define wdt_disable()
#define wdt_enable(x)
#define wdt_reset()
#else
#define wdt_disable()
#define wdt_enable(x) WDT->WDT_MR = 0x3FFF207F
#define wdt_reset() WDT->WDT_CR = 0xA5000001
#endif
// Backlight driver
#define backlightEnable() (PWM->PWM_CH_NUM[0].PWM_CDTY = g_eeGeneral.backlightBright)
#define backlightDisable() (PWM->PWM_CH_NUM[0].PWM_CDTY = 100)
#define isBacklightEnabled() (PWM->PWM_CH_NUM[0].PWM_CDTY != 100)
#define BACKLIGHT_ENABLE() backlightEnable()
#define BACKLIGHT_DISABLE() backlightDisable()
// ADC driver
#define NUM_POTS 3
#define NUM_SLIDERS 0
#define NUM_XPOTS 0
enum Analogs {
STICK1,
STICK2,
STICK3,
STICK4,
POT_FIRST,
POT1 = POT_FIRST,
POT2,
POT3,
POT_LAST = POT3,
TX_VOLTAGE,
#if !defined(REVA)
TX_CURRENT,
#endif
NUM_ANALOGS
};
enum CalibratedAnalogs {
CALIBRATED_STICK1,
CALIBRATED_STICK2,
CALIBRATED_STICK3,
CALIBRATED_STICK4,
CALIBRATED_POT_FIRST,
CALIBRATED_POT1 = CALIBRATED_POT_FIRST,
CALIBRATED_POT2,
CALIBRATED_POT3,
CALIBRATED_POT_LAST = CALIBRATED_POT3,
NUM_CALIBRATED_ANALOGS
};
#define IS_POT(x) ((x)>=POT_FIRST && (x)<=POT_LAST)
#define IS_SLIDER(x) false
void adcInit();
void adcRead(void);
uint16_t getAnalogValue(uint8_t index);
uint16_t getBatteryVoltage(); // returns current battery voltage in 10mV steps
void setSticksGain(uint8_t gains);
// Buzzer driver
void buzzerSound(uint8_t duration);
void buzzerHeartbeat();
#define BUZZER_HEARTBEAT buzzerHeartbeat
// i2c driver
void i2cCheck();
// Coproc driver
void coprocInit();
void coprocWriteData(uint8_t *data, uint32_t size);
#if defined(__cplusplus)
void coprocReadData(bool onlytemp=false);
#endif
extern int8_t volumeRequired;
extern uint8_t Coproc_read;
extern int8_t Coproc_valid;
extern int8_t Coproc_temp;
extern int8_t Coproc_maxtemp;
// Haptic driver
void hapticOff(void);
void hapticOn(uint32_t pwmPercent);
// BlueTooth driver
#if defined(BLUETOOTH)
void btInit();
void btTask(void* pdata);
void btPushByte(uint8_t data);
#endif
// Power driver
#define TRAINER_PWR
#if !defined(REVA)
#define SOFT_PWR_CTRL
#endif
void pwrInit();
void pwrOff();
uint32_t pwrCheck();
uint32_t pwrPressed();
#define UNEXPECTED_SHUTDOWN() (g_eeGeneral.unexpectedShutdown)
// EEPROM driver
#define EEPROM_SIZE (4*1024*1024/8)
#define EEPROM_BLOCK_SIZE (4*1024)
void eepromInit();
uint8_t eepromReadStatus();
uint8_t eepromIsTransferComplete(void);
void eepromBlockErase(uint32_t address);
void eepromStartRead(uint8_t * buffer, size_t address, size_t size);
void eepromStartWrite(uint8_t * buffer, size_t address, size_t size);
// Debug driver
void debugPutc(const char c);
// Telemetry driver
void telemetryPortInit(uint32_t baudrate, uint8_t mode);
uint32_t telemetryTransmitPending();
void telemetryTransmitBuffer(uint8_t * buffer, uint32_t size);
void rxPdcUsart( void (*pChProcess)(uint8_t x) );
// Second UART driver
void serial2TelemetryInit(unsigned int protocol);
#if defined(__cplusplus)
bool telemetrySecondPortReceive(uint8_t & data);
#endif
extern const uint8_t BootCode[];
#endif // _BOARD_SKY9X_H_

View file

@ -1,253 +1,253 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/**
* \file
*
* \par Purpose
*
* Provides the low-level initialization function that gets called on chip startup.
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board_lowlevel.h"
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/** Define clock timeout */
#define CLOCK_TIMEOUT 5000
/** Bit 29 must always be set to 1 when programming the CKGR_PLLAR register.*/
#define PMC_PLLA_SET_BIT29 (0x1 << 29)
/** Specifies the number of Slow Clock cycles x8 before the LOCKA bit is set in PMC_SR after CKGR_PLLAR is written.*/
#define PMC_PLLA_COUNT (0xBF << 8)
/** The PLLA Clock frequency is the PLLA input frequency multiplied by 8*/
#define PMC_PLLA_MULTIPIER (0x07 << 16)
/** PLLA Divider is bypassed.*/
#define PMC_PLLA_DIV (0x01)
void revert_osc( void ) ;
/*----------------------------------------------------------------------------
* Local functions
* returns master_frequency
*----------------------------------------------------------------------------*/
// *** WARNING, this is called BEFORE .data and .bss have been initialised
// *** GLOBAL variables are NOT useable
static uint32_t BOARD_ConfigurePmc(void)
{
/* TODO: configurate PLL in new way */
//#if 0
// uint32_t timeout = 0;
// /** 1: Checking the Main Oscillator Frequency (Optional) and Initialize main oscillator */
// /** 1.1 Initialize main oscillator */
// // TODO:
// /** 2. Setting PLL and Divider*/
// /** 2.1 Initialize PLLA*/
// PMC->CKGR_PLLAR = ( PMC_PLLA_SET_BIT29 |
// PMC_PLLA_MULTIPIER |
// PMC_PLLA_COUNT |
// PMC_PLLA_DIV
// );
// timeout = 0;
// /** 2.2 Wait for the LOCKA bit to be set by polling the status register.*/
// while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (timeout++ < CLOCK_TIMEOUT));
// /** 2.3 wait for the MCKRDY bit to be set by polling the status register*/
// timeout = 0;
// while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
// /** 3. Selection of Master Clock and Processor Clock*/
// PMC->PMC_MCKR |= PMC_MCKR_PRES_CLK_2;
// /** 3.1 wait for the MCKRDY bit to be set by polling the status register*/
// timeout = 0;
// while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
// /** 3.2 PLLA Clock is selected */
// PMC->PMC_MCKR = PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK;
// /** 3.3 wait for the MCKRDY bit to be set by polling the status register*/
// timeout = 0;
// while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
//#endif
#if 1 // old as sam3u
#define AT91C_CKGR_MUL_SHIFT 16
//#define AT91C_CKGR_OUT_SHIFT 14
#define AT91C_CKGR_PLLCOUNT_SHIFT 8
#define AT91C_CKGR_DIV_SHIFT 0
// Settings at 72MHz/2 = 36MHz
#define BOARD_OSCOUNT (CKGR_MOR_MOSCXTST & (0x8 << 8))
#define BOARD_PLLR ((1 << 29) | (0x5 << AT91C_CKGR_MUL_SHIFT) \
| (0x1 << AT91C_CKGR_PLLCOUNT_SHIFT) | (0x2 << AT91C_CKGR_DIV_SHIFT))
#define BOARD_MCKR (PMC_MCKR_CSS_PLLA_CLK)
// Define clock timeout
#undef CLOCK_TIMEOUT
#define CLOCK_TIMEOUT 0xFFFFFFFF
uint32_t timeout = 0 ;
Pmc *pmcptr ;
pmcptr = PMC ;
/* Enable NRST reset
************************************/
//AT91C_BASE_RSTC->RSTC_RMR |= AT91C_RSTC_URSTEN;
/* Select external slow clock
****************************/
// if ((SUPC->SUPC_SR & SUPC_SR_OSCSEL) != SUPC_SR_OSCSEL_CRYST) {
// SUPC->SUPC_CR = SUPC_CR_XTALSEL_CRYSTAL_SEL | ((uint32_t)0xA5 << 24);
// timeout = 0;
// while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST) );
// }
/* Initialize main oscillator
****************************/
if(!(pmcptr->CKGR_MOR & CKGR_MOR_MOSCSEL))
{
pmcptr->CKGR_MOR = (0x37 << 16) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MOSCXTS) && (++timeout < CLOCK_TIMEOUT));
}
/* Switch to 3-20MHz Xtal oscillator */
pmcptr->CKGR_MOR = (0x37 << 16) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MOSCSELS) && (++timeout < CLOCK_TIMEOUT));
pmcptr->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS) | PMC_MCKR_CSS_MAIN_CLK;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MCKRDY) && (++timeout < CLOCK_TIMEOUT));
/* Initialize PLLA 72 MHz */
pmcptr->CKGR_PLLAR = BOARD_PLLR;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_LOCKA) && (++timeout < CLOCK_TIMEOUT));
/* Initialize UTMI for USB usage, can be disabled if not using USB for the sake of saving power*/
//AT91C_BASE_CKGR->CKGR_UCKR |= (AT91C_CKGR_UPLLCOUNT & (3 << 20)) | AT91C_CKGR_UPLLEN;
//timeout = 0;
//while (!(PMC->PMC_SR & AT91C_PMC_LOCKU) && (timeout++ < CLOCK_TIMEOUT));
/* Switch to fast clock
**********************/
// PMC->PMC_MCKR = (BOARD_MCKR & ~PMC_MCKR_CSS) | PMC_MCKR_CSS_MAIN_CLK;
// timeout = 0;
// while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
// Switch to PLLA as main clock 36MHz
PMC->PMC_MCKR = BOARD_MCKR;
timeout = 0;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
#endif
return 36000000L; // Master_frequency
}
void revert_osc()
{
uint32_t timeout = 0;
Pmc *pmcptr;
pmcptr = PMC;
// Switch back to the internal oscillator
pmcptr->CKGR_MOR = (0x37 << 16) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MOSCSELS) && (++timeout < CLOCK_TIMEOUT));
pmcptr->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS) | PMC_MCKR_CSS_SLOW_CLK;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MCKRDY) && (++timeout < CLOCK_TIMEOUT));
pmcptr->CKGR_PLLAR = 1 << 29; // Stop PLLA
}
#if defined(BOOT)
// extern void sam_bootx( void ) ;
// extern void dispUSB( void ) ;
// extern uint32_t init
// ReadTrims( void ) ;
// extern void run_application( void ) ;
static void lowLevelUsbCheck( void )
{
PMC->PMC_PCER0 = (1<<ID_PIOC) ; // Enable clock to PIOC
PIOC->PIO_PER = PIO_PC25 ; // Enable bit C25 (USB-detect)
uint32_t i ;
for ( i = 0 ; i < 50 ; i += 1 ) {
__asm("nop") ;
}
for ( i = 0 ; i < 10 ; i += 1 ) {
if ( PIOC->PIO_PDSR & 0x02000000 ) {
PMC->PMC_PCDR0 = (1<<ID_PIOC) ; // Disable clock to PIOC
dispUSB() ;
sam_bootx() ;
}
}
uint32_t x = initReadTrims() ;
if ((x & 0x42) != 0x42) {
run_application();
}
}
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/**
* \brief Performs the low-level initialization of the chip. This includes EFC,
* master clock and watchdog configuration.
*/
/*----------------------------------------------------------------------------*/
uint32_t SystemInit (void)
{
#if defined(BOOT)
lowLevelUsbCheck() ;
#endif
// Set 2 cycle (1 WS) for Embedded Flash Access
// Max clock is 38 MHz (1.8V VVDCORE)
EFC->EEFC_FMR = (1 << 8) ;
// Configure PMC
return BOARD_ConfigurePmc();
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/**
* \file
*
* \par Purpose
*
* Provides the low-level initialization function that gets called on chip startup.
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board_lowlevel.h"
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/** Define clock timeout */
#define CLOCK_TIMEOUT 5000
/** Bit 29 must always be set to 1 when programming the CKGR_PLLAR register.*/
#define PMC_PLLA_SET_BIT29 (0x1 << 29)
/** Specifies the number of Slow Clock cycles x8 before the LOCKA bit is set in PMC_SR after CKGR_PLLAR is written.*/
#define PMC_PLLA_COUNT (0xBF << 8)
/** The PLLA Clock frequency is the PLLA input frequency multiplied by 8*/
#define PMC_PLLA_MULTIPIER (0x07 << 16)
/** PLLA Divider is bypassed.*/
#define PMC_PLLA_DIV (0x01)
void revert_osc( void ) ;
/*----------------------------------------------------------------------------
* Local functions
* returns master_frequency
*----------------------------------------------------------------------------*/
// *** WARNING, this is called BEFORE .data and .bss have been initialised
// *** GLOBAL variables are NOT useable
static uint32_t BOARD_ConfigurePmc(void)
{
/* TODO: configurate PLL in new way */
//#if 0
// uint32_t timeout = 0;
// /** 1: Checking the Main Oscillator Frequency (Optional) and Initialize main oscillator */
// /** 1.1 Initialize main oscillator */
// // TODO:
// /** 2. Setting PLL and Divider*/
// /** 2.1 Initialize PLLA*/
// PMC->CKGR_PLLAR = ( PMC_PLLA_SET_BIT29 |
// PMC_PLLA_MULTIPIER |
// PMC_PLLA_COUNT |
// PMC_PLLA_DIV
// );
// timeout = 0;
// /** 2.2 Wait for the LOCKA bit to be set by polling the status register.*/
// while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (timeout++ < CLOCK_TIMEOUT));
// /** 2.3 wait for the MCKRDY bit to be set by polling the status register*/
// timeout = 0;
// while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
// /** 3. Selection of Master Clock and Processor Clock*/
// PMC->PMC_MCKR |= PMC_MCKR_PRES_CLK_2;
// /** 3.1 wait for the MCKRDY bit to be set by polling the status register*/
// timeout = 0;
// while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
// /** 3.2 PLLA Clock is selected */
// PMC->PMC_MCKR = PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK;
// /** 3.3 wait for the MCKRDY bit to be set by polling the status register*/
// timeout = 0;
// while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
//#endif
#if 1 // old as sam3u
#define AT91C_CKGR_MUL_SHIFT 16
//#define AT91C_CKGR_OUT_SHIFT 14
#define AT91C_CKGR_PLLCOUNT_SHIFT 8
#define AT91C_CKGR_DIV_SHIFT 0
// Settings at 72MHz/2 = 36MHz
#define BOARD_OSCOUNT (CKGR_MOR_MOSCXTST & (0x8 << 8))
#define BOARD_PLLR ((1 << 29) | (0x5 << AT91C_CKGR_MUL_SHIFT) \
| (0x1 << AT91C_CKGR_PLLCOUNT_SHIFT) | (0x2 << AT91C_CKGR_DIV_SHIFT))
#define BOARD_MCKR (PMC_MCKR_CSS_PLLA_CLK)
// Define clock timeout
#undef CLOCK_TIMEOUT
#define CLOCK_TIMEOUT 0xFFFFFFFF
uint32_t timeout = 0 ;
Pmc *pmcptr ;
pmcptr = PMC ;
/* Enable NRST reset
************************************/
//AT91C_BASE_RSTC->RSTC_RMR |= AT91C_RSTC_URSTEN;
/* Select external slow clock
****************************/
// if ((SUPC->SUPC_SR & SUPC_SR_OSCSEL) != SUPC_SR_OSCSEL_CRYST) {
// SUPC->SUPC_CR = SUPC_CR_XTALSEL_CRYSTAL_SEL | ((uint32_t)0xA5 << 24);
// timeout = 0;
// while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST) );
// }
/* Initialize main oscillator
****************************/
if(!(pmcptr->CKGR_MOR & CKGR_MOR_MOSCSEL))
{
pmcptr->CKGR_MOR = (0x37 << 16) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MOSCXTS) && (++timeout < CLOCK_TIMEOUT));
}
/* Switch to 3-20MHz Xtal oscillator */
pmcptr->CKGR_MOR = (0x37 << 16) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MOSCSELS) && (++timeout < CLOCK_TIMEOUT));
pmcptr->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS) | PMC_MCKR_CSS_MAIN_CLK;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MCKRDY) && (++timeout < CLOCK_TIMEOUT));
/* Initialize PLLA 72 MHz */
pmcptr->CKGR_PLLAR = BOARD_PLLR;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_LOCKA) && (++timeout < CLOCK_TIMEOUT));
/* Initialize UTMI for USB usage, can be disabled if not using USB for the sake of saving power*/
//AT91C_BASE_CKGR->CKGR_UCKR |= (AT91C_CKGR_UPLLCOUNT & (3 << 20)) | AT91C_CKGR_UPLLEN;
//timeout = 0;
//while (!(PMC->PMC_SR & AT91C_PMC_LOCKU) && (timeout++ < CLOCK_TIMEOUT));
/* Switch to fast clock
**********************/
// PMC->PMC_MCKR = (BOARD_MCKR & ~PMC_MCKR_CSS) | PMC_MCKR_CSS_MAIN_CLK;
// timeout = 0;
// while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
// Switch to PLLA as main clock 36MHz
PMC->PMC_MCKR = BOARD_MCKR;
timeout = 0;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT));
#endif
return 36000000L; // Master_frequency
}
void revert_osc()
{
uint32_t timeout = 0;
Pmc *pmcptr;
pmcptr = PMC;
// Switch back to the internal oscillator
pmcptr->CKGR_MOR = (0x37 << 16) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MOSCSELS) && (++timeout < CLOCK_TIMEOUT));
pmcptr->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS) | PMC_MCKR_CSS_SLOW_CLK;
timeout = 0;
while (!(pmcptr->PMC_SR & PMC_SR_MCKRDY) && (++timeout < CLOCK_TIMEOUT));
pmcptr->CKGR_PLLAR = 1 << 29; // Stop PLLA
}
#if defined(BOOT)
// extern void sam_bootx( void ) ;
// extern void dispUSB( void ) ;
// extern uint32_t init
// ReadTrims( void ) ;
// extern void run_application( void ) ;
static void lowLevelUsbCheck( void )
{
PMC->PMC_PCER0 = (1<<ID_PIOC) ; // Enable clock to PIOC
PIOC->PIO_PER = PIO_PC25 ; // Enable bit C25 (USB-detect)
uint32_t i ;
for ( i = 0 ; i < 50 ; i += 1 ) {
__asm("nop") ;
}
for ( i = 0 ; i < 10 ; i += 1 ) {
if ( PIOC->PIO_PDSR & 0x02000000 ) {
PMC->PMC_PCDR0 = (1<<ID_PIOC) ; // Disable clock to PIOC
dispUSB() ;
sam_bootx() ;
}
}
uint32_t x = initReadTrims() ;
if ((x & 0x42) != 0x42) {
run_application();
}
}
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/**
* \brief Performs the low-level initialization of the chip. This includes EFC,
* master clock and watchdog configuration.
*/
/*----------------------------------------------------------------------------*/
uint32_t SystemInit (void)
{
#if defined(BOOT)
lowLevelUsbCheck() ;
#endif
// Set 2 cycle (1 WS) for Embedded Flash Access
// Max clock is 38 MHz (1.8V VVDCORE)
EFC->EEFC_FMR = (1 << 8) ;
// Configure PMC
return BOARD_ConfigurePmc();
}

File diff suppressed because it is too large Load diff

View file

@ -1,59 +1,59 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
volatile uint8_t buzzerCount ;
#if defined(REVA)
void buzzerOn()
{
PIOA->PIO_SODR = 0x00010000L ; // Set bit A16 ON
}
void buzzerOff()
{
PIOA->PIO_CODR = 0x00010000L ; // Set bit A16 ON
}
#else
void buzzerOn()
{
PIOA->PIO_SODR = 0x02000000L ; // Set bit A25 ON
}
void buzzerOff()
{
PIOA->PIO_CODR = 0x02000000L ; // Set bit A25 ON
}
#endif
void buzzerSound(uint8_t duration)
{
buzzerOn();
buzzerCount = duration;
}
void buzzerHeartbeat()
{
if (buzzerCount) {
if (--buzzerCount == 0)
buzzerOff();
}
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
volatile uint8_t buzzerCount ;
#if defined(REVA)
void buzzerOn()
{
PIOA->PIO_SODR = 0x00010000L ; // Set bit A16 ON
}
void buzzerOff()
{
PIOA->PIO_CODR = 0x00010000L ; // Set bit A16 ON
}
#else
void buzzerOn()
{
PIOA->PIO_SODR = 0x02000000L ; // Set bit A25 ON
}
void buzzerOff()
{
PIOA->PIO_CODR = 0x02000000L ; // Set bit A25 ON
}
#endif
void buzzerSound(uint8_t duration)
{
buzzerOn();
buzzerCount = duration;
}
void buzzerHeartbeat()
{
if (buzzerCount) {
if (--buzzerCount == 0)
buzzerOff();
}
}

View file

@ -18,104 +18,104 @@
* GNU General Public License for more details.
*/
//------------------------------------------------------------------------------
/// \unit
/// !Purpose
///
/// Definition of AT91SAM3S4 characteristics and features
///
/// !Usage
/// -# For ARM core feature, see "AT91SAM3S4 - ARM core features".
/// -# For IP features, see "AT91SAM3S4 - IP features".
/// -# For misc, see "AT91SAM3S4 - Misc".
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// \unit
/// !Purpose
///
/// Definition of AT91SAM3S4 characteristics and features
///
/// !Usage
/// -# For ARM core feature, see "AT91SAM3S4 - ARM core features".
/// -# For IP features, see "AT91SAM3S4 - IP features".
/// -# For misc, see "AT91SAM3S4 - Misc".
//------------------------------------------------------------------------------
#ifndef _CHIP_H_
#define _CHIP_H_
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// \page "AT91SAM3S4 - ARM core features"
/// This page lists several characteristics related to the ARM core
///
//ARM core features
/// ARM core definition.
#define cortexm3
/// family definition.
#define at91sam3s
//------------------------------------------------------------------------------
/// \page "AT91SAM3S4 - IP features"
/// This page lists several characteristics related to the embedded IP
///
//IP FEATURES
// EFC GPNVM number
#define CHIP_EFC_NUM_GPNVMS 3
/// Indicates chip has an Enhanced EFC.
#define CHIP_FLASH_EEFC
// DMA channels number
#define CHIP_DMA_CHANNEL_NUM 4
// Indicate chip's MCI interface.
#define MCI2_INTERFACE
// Indicate chip SSC has DMA interface.
#define CHIP_SSC_DMA
// Indicate chip SPI has DMA interface.
#define CHIP_SPI_DMA
/// Indicates chip has an UDP Full Speed.
#define CHIP_USB_UDP
/// Indicates chip has an internal pull-up.
#define CHIP_USB_PULLUP_INTERNAL
/// Number of USB endpoints
#define CHIP_USB_NUMENDPOINTS 8
/// Endpoints max paxcket size
#define CHIP_USB_ENDPOINTS_MAXPACKETSIZE(i) \
((i == 0) ? 64 : \
((i == 1) ? 64 : \
((i == 2) ? 64 : \
((i == 3) ? 64 : \
((i == 4) ? 512 : \
((i == 5) ? 512 : \
((i == 6) ? 64 : \
((i == 7) ? 64 : 0 ))))))))
/// Endpoints Number of Bank
#define CHIP_USB_ENDPOINTS_BANKS(i) \
((i == 0) ? 1 : \
((i == 1) ? 2 : \
((i == 2) ? 2 : \
((i == 3) ? 1 : \
((i == 4) ? 2 : \
((i == 5) ? 2 : \
((i == 6) ? 2 : \
((i == 7) ? 2 : 0 ))))))))
//------------------------------------------------------------------------------
/// \page "AT91SAM3S4 - Misc "
/// This page lists misc features
///
//Misc
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// \page "AT91SAM3S4 - ARM core features"
/// This page lists several characteristics related to the ARM core
///
//ARM core features
/// ARM core definition.
#define cortexm3
/// family definition.
#define at91sam3s
//------------------------------------------------------------------------------
/// \page "AT91SAM3S4 - IP features"
/// This page lists several characteristics related to the embedded IP
///
//IP FEATURES
// EFC GPNVM number
#define CHIP_EFC_NUM_GPNVMS 3
/// Indicates chip has an Enhanced EFC.
#define CHIP_FLASH_EEFC
// DMA channels number
#define CHIP_DMA_CHANNEL_NUM 4
// Indicate chip's MCI interface.
#define MCI2_INTERFACE
// Indicate chip SSC has DMA interface.
#define CHIP_SSC_DMA
// Indicate chip SPI has DMA interface.
#define CHIP_SPI_DMA
/// Indicates chip has an UDP Full Speed.
#define CHIP_USB_UDP
/// Indicates chip has an internal pull-up.
#define CHIP_USB_PULLUP_INTERNAL
/// Number of USB endpoints
#define CHIP_USB_NUMENDPOINTS 8
/// Endpoints max paxcket size
#define CHIP_USB_ENDPOINTS_MAXPACKETSIZE(i) \
((i == 0) ? 64 : \
((i == 1) ? 64 : \
((i == 2) ? 64 : \
((i == 3) ? 64 : \
((i == 4) ? 512 : \
((i == 5) ? 512 : \
((i == 6) ? 64 : \
((i == 7) ? 64 : 0 ))))))))
/// Endpoints Number of Bank
#define CHIP_USB_ENDPOINTS_BANKS(i) \
((i == 0) ? 1 : \
((i == 1) ? 2 : \
((i == 2) ? 2 : \
((i == 3) ? 1 : \
((i == 4) ? 2 : \
((i == 5) ? 2 : \
((i == 6) ? 2 : \
((i == 7) ? 2 : 0 ))))))))
//------------------------------------------------------------------------------
/// \page "AT91SAM3S4 - Misc "
/// This page lists misc features
///
//Misc
#endif // _CHIP_H_

View file

@ -1,205 +1,205 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
int8_t volumeRequired ;
uint8_t coprocReadDataPending ;
uint8_t coprocWriteDataPending ;
uint8_t CoProc_appgo_pending ;
uint8_t Volume_read ;
uint8_t Coproc_read ;
int8_t Coproc_temp ;
int8_t Coproc_maxtemp=-127 ;
int8_t Coproc_valid ;
bool get_onlytemp;
#if !defined(SIMU)
// TODO not used? static uint8_t *Twi_read_address ;
#endif
static uint8_t TwiOperation ;
#define TWI_NONE 0
#define TWI_WRITE_VOL 2
#define TWI_READ_COPROC 3
#define TWI_COPROC_APPGO 4
#define TWI_WAIT_STOP 5
#define TWI_WRITE_COPROC 6
// Commands to the coprocessor bootloader/application
#define TWI_CMD_PAGEUPDATE 0x01 // TWI Command to program a flash page
#define TWI_CMD_EXECUTEAPP 0x02 // TWI Command to jump to the application program
#define TWI_CMD_SETREAD_ADDRESS 0x03 // TWI Command to set address to read from
#define TWI_CMD_WRITE_DATA 0x04 // TWI Command send data to the application
#define COPROC_RX_BUXSIZE 22
uint8_t Co_proc_status[COPROC_RX_BUXSIZE] ;
uint8_t *coprocWriteDataPtr ;
uint32_t coprocWriteDataSize ;
// This is called from an interrupt routine, or
// interrupts must be disabled while it is called
// from elsewhere.
void i2cCheck()
{
if ( TWI0->TWI_IMR & TWI_IMR_TXCOMP ) {
return ; // Busy
}
if ( volumeRequired >= 0 ) { // Set volume to this value
TWI0->TWI_MMR = 0x002F0000 ; // Device 5E (>>1) and master is writing
TwiOperation = TWI_WRITE_VOL ;
TWI0->TWI_THR = volumeRequired ; // Send data
volumeRequired = -1 ;
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
else if (coprocReadDataPending) {
Coproc_valid = 0 ;
coprocReadDataPending = 0 ;
TWI0->TWI_MMR = 0x00351000 ; // Device 35 and master is reading
TwiOperation = TWI_READ_COPROC ;
#ifndef SIMU
TWI0->TWI_RPR = (uint32_t)&Co_proc_status[0] ;
#endif
TWI0->TWI_RCR = COPROC_RX_BUXSIZE - 1 ;
if ( TWI0->TWI_SR & TWI_SR_RXRDY ) {
(void) TWI0->TWI_RHR ;
}
TWI0->TWI_PTCR = TWI_PTCR_RXTEN ; // Start transfers
TWI0->TWI_CR = TWI_CR_START ; // Start Rx
TWI0->TWI_IER = TWI_IER_RXBUFF | TWI_IER_TXCOMP ;
}
else if ( CoProc_appgo_pending ) {
CoProc_appgo_pending = 0 ;
TWI0->TWI_MMR = 0x00350000 ; // Device 35 and master is writing
TwiOperation = TWI_COPROC_APPGO ;
TWI0->TWI_THR = TWI_CMD_EXECUTEAPP ; // Send appgo command
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
else if ( coprocWriteDataPending ) {
coprocWriteDataPending = 0 ;
TWI0->TWI_MMR = 0x00350000 ; // Device 35 and master is writing
TwiOperation = TWI_WRITE_COPROC ;
#ifndef SIMU
TWI0->TWI_TPR = (uint32_t)coprocWriteDataPtr ;
#endif
TWI0->TWI_TCR = coprocWriteDataSize ;
TWI0->TWI_THR = TWI_CMD_WRITE_DATA ; // Send write command
TWI0->TWI_PTCR = TWI_PTCR_TXTEN ; // Start data transfer
TWI0->TWI_IER = TWI_IER_TXBUFE | TWI_IER_TXCOMP ;
}
}
void coprocReadData(bool onlytemp)
{
get_onlytemp = onlytemp;
coprocReadDataPending = 1 ;
__disable_irq() ;
i2cCheck() ;
__enable_irq() ;
}
void coprocWriteData(uint8_t *data, uint32_t size)
{
coprocWriteDataPtr = data;
coprocWriteDataSize = size;
coprocWriteDataPending = 1;
__disable_irq();
i2cCheck();
__enable_irq();
}
#if !defined(SIMU)
extern "C" void TWI0_IRQHandler()
{
if ( TwiOperation == TWI_READ_COPROC )
{
if ( TWI0->TWI_SR & TWI_SR_RXBUFF )
{
TWI0->TWI_IDR = TWI_IDR_RXBUFF ;
TwiOperation = TWI_WAIT_STOP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Rx
TWI0->TWI_RCR = 1 ; // Last byte
return ;
}
else
{
Coproc_valid = -1 ;
}
}
if ( TwiOperation == TWI_WAIT_STOP )
{
Coproc_valid = 1 ;
Coproc_read = Co_proc_status[0] ;
if ( Coproc_read & 0x80 ) {
// Bootloader
CoProc_appgo_pending = 1 ; // Action application
}
else {
// Got data from tiny app
// Set the date and time
struct gtm utm;
if (!get_onlytemp) {
utm.tm_sec = Co_proc_status[1] ;
utm.tm_min = Co_proc_status[2] ;
utm.tm_hour = Co_proc_status[3] ;
utm.tm_mday = Co_proc_status[4] ;
utm.tm_mon = Co_proc_status[5] - 1;
utm.tm_year = (Co_proc_status[6] + ( Co_proc_status[7] << 8 )) - TM_YEAR_BASE;
g_rtcTime = gmktime(&utm);
}
Coproc_temp = Co_proc_status[8];
if (Coproc_temp > Coproc_maxtemp)
Coproc_maxtemp=Coproc_temp;
}
TWI0->TWI_PTCR = TWI_PTCR_RXTDIS ; // Stop transfers
if ( TWI0->TWI_SR & TWI_SR_RXRDY ) {
(void) TWI0->TWI_RHR ; // Discard any rubbish data
}
}
// if ( TwiOperation == TWI_WRITE_VOL )
// {
// }
if ( TwiOperation == TWI_WRITE_COPROC )
{
if ( TWI0->TWI_SR & TWI_SR_TXBUFE )
{
TWI0->TWI_IDR = TWI_IDR_TXBUFE ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
TWI0->TWI_PTCR = TWI_PTCR_TXTDIS ; // Stop transfers
TwiOperation = TWI_NONE ;
return ;
}
}
TWI0->TWI_IDR = TWI_IDR_TXCOMP | TWI_IDR_TXBUFE | TWI_IDR_RXBUFF ;
TWI0->TWI_PTCR = TWI_PTCR_TXTDIS | TWI_PTCR_RXTDIS ; // Stop transfers
if ( TWI0->TWI_SR & TWI_SR_NACK )
{
}
TwiOperation = TWI_NONE ;
i2cCheck() ;
}
#endif
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
int8_t volumeRequired ;
uint8_t coprocReadDataPending ;
uint8_t coprocWriteDataPending ;
uint8_t CoProc_appgo_pending ;
uint8_t Volume_read ;
uint8_t Coproc_read ;
int8_t Coproc_temp ;
int8_t Coproc_maxtemp=-127 ;
int8_t Coproc_valid ;
bool get_onlytemp;
#if !defined(SIMU)
// TODO not used? static uint8_t *Twi_read_address ;
#endif
static uint8_t TwiOperation ;
#define TWI_NONE 0
#define TWI_WRITE_VOL 2
#define TWI_READ_COPROC 3
#define TWI_COPROC_APPGO 4
#define TWI_WAIT_STOP 5
#define TWI_WRITE_COPROC 6
// Commands to the coprocessor bootloader/application
#define TWI_CMD_PAGEUPDATE 0x01 // TWI Command to program a flash page
#define TWI_CMD_EXECUTEAPP 0x02 // TWI Command to jump to the application program
#define TWI_CMD_SETREAD_ADDRESS 0x03 // TWI Command to set address to read from
#define TWI_CMD_WRITE_DATA 0x04 // TWI Command send data to the application
#define COPROC_RX_BUXSIZE 22
uint8_t Co_proc_status[COPROC_RX_BUXSIZE] ;
uint8_t *coprocWriteDataPtr ;
uint32_t coprocWriteDataSize ;
// This is called from an interrupt routine, or
// interrupts must be disabled while it is called
// from elsewhere.
void i2cCheck()
{
if ( TWI0->TWI_IMR & TWI_IMR_TXCOMP ) {
return ; // Busy
}
if ( volumeRequired >= 0 ) { // Set volume to this value
TWI0->TWI_MMR = 0x002F0000 ; // Device 5E (>>1) and master is writing
TwiOperation = TWI_WRITE_VOL ;
TWI0->TWI_THR = volumeRequired ; // Send data
volumeRequired = -1 ;
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
else if (coprocReadDataPending) {
Coproc_valid = 0 ;
coprocReadDataPending = 0 ;
TWI0->TWI_MMR = 0x00351000 ; // Device 35 and master is reading
TwiOperation = TWI_READ_COPROC ;
#ifndef SIMU
TWI0->TWI_RPR = (uint32_t)&Co_proc_status[0] ;
#endif
TWI0->TWI_RCR = COPROC_RX_BUXSIZE - 1 ;
if ( TWI0->TWI_SR & TWI_SR_RXRDY ) {
(void) TWI0->TWI_RHR ;
}
TWI0->TWI_PTCR = TWI_PTCR_RXTEN ; // Start transfers
TWI0->TWI_CR = TWI_CR_START ; // Start Rx
TWI0->TWI_IER = TWI_IER_RXBUFF | TWI_IER_TXCOMP ;
}
else if ( CoProc_appgo_pending ) {
CoProc_appgo_pending = 0 ;
TWI0->TWI_MMR = 0x00350000 ; // Device 35 and master is writing
TwiOperation = TWI_COPROC_APPGO ;
TWI0->TWI_THR = TWI_CMD_EXECUTEAPP ; // Send appgo command
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
else if ( coprocWriteDataPending ) {
coprocWriteDataPending = 0 ;
TWI0->TWI_MMR = 0x00350000 ; // Device 35 and master is writing
TwiOperation = TWI_WRITE_COPROC ;
#ifndef SIMU
TWI0->TWI_TPR = (uint32_t)coprocWriteDataPtr ;
#endif
TWI0->TWI_TCR = coprocWriteDataSize ;
TWI0->TWI_THR = TWI_CMD_WRITE_DATA ; // Send write command
TWI0->TWI_PTCR = TWI_PTCR_TXTEN ; // Start data transfer
TWI0->TWI_IER = TWI_IER_TXBUFE | TWI_IER_TXCOMP ;
}
}
void coprocReadData(bool onlytemp)
{
get_onlytemp = onlytemp;
coprocReadDataPending = 1 ;
__disable_irq() ;
i2cCheck() ;
__enable_irq() ;
}
void coprocWriteData(uint8_t *data, uint32_t size)
{
coprocWriteDataPtr = data;
coprocWriteDataSize = size;
coprocWriteDataPending = 1;
__disable_irq();
i2cCheck();
__enable_irq();
}
#if !defined(SIMU)
extern "C" void TWI0_IRQHandler()
{
if ( TwiOperation == TWI_READ_COPROC )
{
if ( TWI0->TWI_SR & TWI_SR_RXBUFF )
{
TWI0->TWI_IDR = TWI_IDR_RXBUFF ;
TwiOperation = TWI_WAIT_STOP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Rx
TWI0->TWI_RCR = 1 ; // Last byte
return ;
}
else
{
Coproc_valid = -1 ;
}
}
if ( TwiOperation == TWI_WAIT_STOP )
{
Coproc_valid = 1 ;
Coproc_read = Co_proc_status[0] ;
if ( Coproc_read & 0x80 ) {
// Bootloader
CoProc_appgo_pending = 1 ; // Action application
}
else {
// Got data from tiny app
// Set the date and time
struct gtm utm;
if (!get_onlytemp) {
utm.tm_sec = Co_proc_status[1] ;
utm.tm_min = Co_proc_status[2] ;
utm.tm_hour = Co_proc_status[3] ;
utm.tm_mday = Co_proc_status[4] ;
utm.tm_mon = Co_proc_status[5] - 1;
utm.tm_year = (Co_proc_status[6] + ( Co_proc_status[7] << 8 )) - TM_YEAR_BASE;
g_rtcTime = gmktime(&utm);
}
Coproc_temp = Co_proc_status[8];
if (Coproc_temp > Coproc_maxtemp)
Coproc_maxtemp=Coproc_temp;
}
TWI0->TWI_PTCR = TWI_PTCR_RXTDIS ; // Stop transfers
if ( TWI0->TWI_SR & TWI_SR_RXRDY ) {
(void) TWI0->TWI_RHR ; // Discard any rubbish data
}
}
// if ( TwiOperation == TWI_WRITE_VOL )
// {
// }
if ( TwiOperation == TWI_WRITE_COPROC )
{
if ( TWI0->TWI_SR & TWI_SR_TXBUFE )
{
TWI0->TWI_IDR = TWI_IDR_TXBUFE ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
TWI0->TWI_PTCR = TWI_PTCR_TXTDIS ; // Stop transfers
TwiOperation = TWI_NONE ;
return ;
}
}
TWI0->TWI_IDR = TWI_IDR_TXCOMP | TWI_IDR_TXBUFE | TWI_IDR_RXBUFF ;
TWI0->TWI_PTCR = TWI_PTCR_TXTDIS | TWI_PTCR_RXTDIS ; // Stop transfers
if ( TWI0->TWI_SR & TWI_SR_NACK )
{
}
TwiOperation = TWI_NONE ;
i2cCheck() ;
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,131 +1,131 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define __CRT_C__
#include <stdint.h>
/*=========================================================================*/
/* DEFINE: All extern Data */
/*=========================================================================*/
/*
* The next data are defined by the linker script.
*/
extern unsigned long _stext;
extern unsigned long _etext;
extern unsigned long _sdata;
extern unsigned long _edata;
extern unsigned long _sbss;
extern unsigned long _ebss;
extern unsigned long _estack;
/* This is the main */
extern int main (void);
/*=========================================================================*/
/* DEFINE: Prototypes */
/*=========================================================================*/
extern uint32_t SystemInit (void) ; // __attribute__((weak));
/*=========================================================================*/
/* DEFINE: All code exported */
/*=========================================================================*/
/***************************************************************************/
/* SystemInit */
/* */
/* SystemInit is a function which is provided by the CMSIS interface. */
/* If this function is not available, we need a function here to prevent */
/* an error of the linker. Therefore this function is declared as weak. */
/***************************************************************************/
//uint32_t SystemInit (void)
//{
//} /* SystemInit */
extern uint32_t Master_frequency ;
/***************************************************************************/
/* ResetHandler */
/* */
/* This function is used for the C runtime initialisation, */
/* for handling the .data and .bss segments. */
/***************************************************************************/
void ResetHandler (void)
{
{
uint32_t *pSrc;
uint32_t *pDest;
uint32_t m_freq ;
/*
* Call the SystemInit code from CMSIS interface if available.
* SystemInit is a week function which can be override
* by an external function.
*/
m_freq = SystemInit();
/*
* Set the "Vector Table Offset Register". From the ARM
* documentation, we got the following information:
*
* Use the Vector Table Offset Register to determine:
* - if the vector table is in RAM or code memory
* - the vector table offset.
*/
*((uint32_t*)0xE000ED08) = (uint32_t)&_stext;
/*
* Copy the initialized data of the ".data" segment
* from the flash to the are in the ram.
*/
pSrc = &_etext;
pDest = &_sdata;
while(pDest < &_edata)
{
*pDest++ = *pSrc++;
}
/*
* Clear the ".bss" segment.
*/
pDest = &_sbss;
while(pDest < &_ebss)
{
*pDest++ = 0;
}
Master_frequency = m_freq ;
}
/*
* And now the main function can be called.
* Scotty, energie...
*/
main();
/*
* In case there are problems with the
* "warp drive", stop here.
*/
while(1) {};
} /* ResetHandler */
/*** EOF ***/
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define __CRT_C__
#include <stdint.h>
/*=========================================================================*/
/* DEFINE: All extern Data */
/*=========================================================================*/
/*
* The next data are defined by the linker script.
*/
extern unsigned long _stext;
extern unsigned long _etext;
extern unsigned long _sdata;
extern unsigned long _edata;
extern unsigned long _sbss;
extern unsigned long _ebss;
extern unsigned long _estack;
/* This is the main */
extern int main (void);
/*=========================================================================*/
/* DEFINE: Prototypes */
/*=========================================================================*/
extern uint32_t SystemInit (void) ; // __attribute__((weak));
/*=========================================================================*/
/* DEFINE: All code exported */
/*=========================================================================*/
/***************************************************************************/
/* SystemInit */
/* */
/* SystemInit is a function which is provided by the CMSIS interface. */
/* If this function is not available, we need a function here to prevent */
/* an error of the linker. Therefore this function is declared as weak. */
/***************************************************************************/
//uint32_t SystemInit (void)
//{
//} /* SystemInit */
extern uint32_t Master_frequency ;
/***************************************************************************/
/* ResetHandler */
/* */
/* This function is used for the C runtime initialisation, */
/* for handling the .data and .bss segments. */
/***************************************************************************/
void ResetHandler (void)
{
{
uint32_t *pSrc;
uint32_t *pDest;
uint32_t m_freq ;
/*
* Call the SystemInit code from CMSIS interface if available.
* SystemInit is a week function which can be override
* by an external function.
*/
m_freq = SystemInit();
/*
* Set the "Vector Table Offset Register". From the ARM
* documentation, we got the following information:
*
* Use the Vector Table Offset Register to determine:
* - if the vector table is in RAM or code memory
* - the vector table offset.
*/
*((uint32_t*)0xE000ED08) = (uint32_t)&_stext;
/*
* Copy the initialized data of the ".data" segment
* from the flash to the are in the ram.
*/
pSrc = &_etext;
pDest = &_sdata;
while(pDest < &_edata)
{
*pDest++ = *pSrc++;
}
/*
* Clear the ".bss" segment.
*/
pDest = &_sbss;
while(pDest < &_ebss)
{
*pDest++ = 0;
}
Master_frequency = m_freq ;
}
/*
* And now the main function can be called.
* Scotty, energie...
*/
main();
/*
* In case there are problems with the
* "warp drive", stop here.
*/
while(1) {};
} /* ResetHandler */
/*** EOF ***/

File diff suppressed because it is too large Load diff

View file

@ -1,200 +1,200 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
volatile uint8_t Spi_complete = 1;
uint8_t Spi_tx_buf[24];
uint8_t eepromIsTransferComplete()
{
return Spi_complete;
}
uint32_t eepromTransmitData(uint8_t *command, uint8_t *tx, uint8_t *rx, uint32_t comlen, uint32_t count)
{
Spi * spiptr = SPI;
uint32_t condition;
static uint8_t discard_rx_command[4];
if (comlen > 4) {
return 0x4FFFF;
}
Spi_complete = 0;
condition = SPI_SR_TXEMPTY;
spiptr->SPI_CR = 1; // Enable
(void) spiptr->SPI_RDR; // Dump any rx data
(void) spiptr->SPI_SR; // Clear error flags
spiptr->SPI_RPR = (uint32_t)discard_rx_command;
spiptr->SPI_RCR = comlen;
if (rx) {
spiptr->SPI_RNPR = (uint32_t)rx;
spiptr->SPI_RNCR = count;
condition = SPI_SR_RXBUFF;
}
spiptr->SPI_TPR = (uint32_t)command;
spiptr->SPI_TCR = comlen;
if (tx) {
spiptr->SPI_TNPR = (uint32_t)tx;
}
else {
spiptr->SPI_TNPR = (uint32_t)rx;
}
spiptr->SPI_TNCR = count;
spiptr->SPI_PTCR = SPI_PTCR_RXTEN | SPI_PTCR_TXTEN; // Start transfers
// Wait for things to get started, avoids early interrupt
for (count = 0; count < 1000; count += 1) {
if ((spiptr->SPI_SR & SPI_SR_TXEMPTY) == 0)
{
break;
}
}
spiptr->SPI_IER = condition;
return 0;
}
uint8_t eepromTransmitByte(uint8_t out, bool skipFirst)
{
Spi * spiptr = SPI;
uint32_t delay;
spiptr->SPI_CR = 1; // Enable
(void) spiptr->SPI_RDR; // Dump any rx data
spiptr->SPI_TDR = out;
delay = 0;
while ((spiptr->SPI_SR & SPI_SR_RDRF) == 0) {
// wait for received
if (++delay > 10000) {
break;
}
}
if (skipFirst) {
(void) spiptr->SPI_RDR; // Dump the rx data
spiptr->SPI_TDR = 0;
delay = 0;
while ((spiptr->SPI_SR & SPI_SR_RDRF) == 0) {
// wait for received
if (++delay > 10000) {
break;
}
}
}
spiptr->SPI_CR = 2; // Disable
return spiptr->SPI_RDR;
}
enum EepromCommand {
COMMAND_WRITE_STATUS_REGISTER = 0x01,
COMMAND_BYTE_PROGRAM = 0x02,
COMMAND_READ_ARRAY = 0x03,
COMMAND_READ_STATUS = 0x05,
COMMAND_WRITE_ENABLE = 0x06,
COMMAND_BLOCK_ERASE = 0x20,
};
void eepromPrepareCommand(EepromCommand command, uint32_t address)
{
uint8_t * p = Spi_tx_buf;
*p = command;
*(p+1) = address >> 16;
*(p+2) = address >> 8;
*(p+3) = address;
}
uint8_t eepromReadStatus()
{
uint8_t read_status = eepromTransmitByte(COMMAND_READ_STATUS, true);
return !(read_status & 1);
}
void eepromWriteStatusRegister()
{
eepromTransmitByte(COMMAND_WRITE_STATUS_REGISTER, true);
}
void eepromWriteEnable()
{
eepromTransmitByte(COMMAND_WRITE_ENABLE, false);
}
void eepromStartWrite(uint8_t * buffer, size_t address, size_t size)
{
eepromWriteEnable();
eepromPrepareCommand(COMMAND_BYTE_PROGRAM, address);
eepromTransmitData(Spi_tx_buf, buffer, 0, 4, size);
}
void eepromStartRead(uint8_t * buffer, size_t address, size_t size)
{
eepromPrepareCommand(COMMAND_READ_ARRAY, address);
eepromTransmitData(Spi_tx_buf, 0, buffer, 4, size);
}
void eepromBlockErase(uint32_t address)
{
eepromWriteEnable();
eepromPrepareCommand(COMMAND_BLOCK_ERASE, address);
eepromTransmitData(Spi_tx_buf, 0, 0, 4, 0);
}
// SPI i/f to EEPROM (4Mb)
// Peripheral ID 21 (0x00200000)
// Connections:
// SS PA11 (peripheral A)
// MISO PA12 (peripheral A)
// MOSI PA13 (peripheral A)
// SCK PA14 (peripheral A)
// Set clock to 3 MHz, AT25 device is rated to 70MHz, 18MHz would be better
void eepromInit()
{
Spi * spiptr = SPI;
uint32_t timer;
PMC->PMC_PCER0 |= 0x00200000L; // Enable peripheral clock to SPI
/* Configure PIO */
configure_pins(0x00007800, PIN_PERIPHERAL | PIN_INPUT | PIN_PER_A | PIN_PORTA | PIN_NO_PULLUP);
timer = (Master_frequency / 3000000) << 8; // Baud rate 3Mb/s
spiptr->SPI_MR = 0x14000011; // 0001 0100 0000 0000 0000 0000 0001 0001 Master
spiptr->SPI_CSR[0] = 0x01180009 | timer; // 0000 0001 0001 1000 xxxx xxxx 0000 1001
NVIC_EnableIRQ(SPI_IRQn);
eepromWriteEnable();
eepromWriteStatusRegister();
}
extern "C" void SPI_IRQHandler()
{
Spi * spiptr = SPI;
SPI->SPI_IDR = 0x07FF; // All interrupts off
spiptr->SPI_CR = 2; // Disable
(void) spiptr->SPI_RDR; // Dump any rx data
(void) spiptr->SPI_SR; // Clear error flags
spiptr->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS; // Stop tramsfers
Spi_complete = 1; // Indicate completion
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
volatile uint8_t Spi_complete = 1;
uint8_t Spi_tx_buf[24];
uint8_t eepromIsTransferComplete()
{
return Spi_complete;
}
uint32_t eepromTransmitData(uint8_t *command, uint8_t *tx, uint8_t *rx, uint32_t comlen, uint32_t count)
{
Spi * spiptr = SPI;
uint32_t condition;
static uint8_t discard_rx_command[4];
if (comlen > 4) {
return 0x4FFFF;
}
Spi_complete = 0;
condition = SPI_SR_TXEMPTY;
spiptr->SPI_CR = 1; // Enable
(void) spiptr->SPI_RDR; // Dump any rx data
(void) spiptr->SPI_SR; // Clear error flags
spiptr->SPI_RPR = (uint32_t)discard_rx_command;
spiptr->SPI_RCR = comlen;
if (rx) {
spiptr->SPI_RNPR = (uint32_t)rx;
spiptr->SPI_RNCR = count;
condition = SPI_SR_RXBUFF;
}
spiptr->SPI_TPR = (uint32_t)command;
spiptr->SPI_TCR = comlen;
if (tx) {
spiptr->SPI_TNPR = (uint32_t)tx;
}
else {
spiptr->SPI_TNPR = (uint32_t)rx;
}
spiptr->SPI_TNCR = count;
spiptr->SPI_PTCR = SPI_PTCR_RXTEN | SPI_PTCR_TXTEN; // Start transfers
// Wait for things to get started, avoids early interrupt
for (count = 0; count < 1000; count += 1) {
if ((spiptr->SPI_SR & SPI_SR_TXEMPTY) == 0)
{
break;
}
}
spiptr->SPI_IER = condition;
return 0;
}
uint8_t eepromTransmitByte(uint8_t out, bool skipFirst)
{
Spi * spiptr = SPI;
uint32_t delay;
spiptr->SPI_CR = 1; // Enable
(void) spiptr->SPI_RDR; // Dump any rx data
spiptr->SPI_TDR = out;
delay = 0;
while ((spiptr->SPI_SR & SPI_SR_RDRF) == 0) {
// wait for received
if (++delay > 10000) {
break;
}
}
if (skipFirst) {
(void) spiptr->SPI_RDR; // Dump the rx data
spiptr->SPI_TDR = 0;
delay = 0;
while ((spiptr->SPI_SR & SPI_SR_RDRF) == 0) {
// wait for received
if (++delay > 10000) {
break;
}
}
}
spiptr->SPI_CR = 2; // Disable
return spiptr->SPI_RDR;
}
enum EepromCommand {
COMMAND_WRITE_STATUS_REGISTER = 0x01,
COMMAND_BYTE_PROGRAM = 0x02,
COMMAND_READ_ARRAY = 0x03,
COMMAND_READ_STATUS = 0x05,
COMMAND_WRITE_ENABLE = 0x06,
COMMAND_BLOCK_ERASE = 0x20,
};
void eepromPrepareCommand(EepromCommand command, uint32_t address)
{
uint8_t * p = Spi_tx_buf;
*p = command;
*(p+1) = address >> 16;
*(p+2) = address >> 8;
*(p+3) = address;
}
uint8_t eepromReadStatus()
{
uint8_t read_status = eepromTransmitByte(COMMAND_READ_STATUS, true);
return !(read_status & 1);
}
void eepromWriteStatusRegister()
{
eepromTransmitByte(COMMAND_WRITE_STATUS_REGISTER, true);
}
void eepromWriteEnable()
{
eepromTransmitByte(COMMAND_WRITE_ENABLE, false);
}
void eepromStartWrite(uint8_t * buffer, size_t address, size_t size)
{
eepromWriteEnable();
eepromPrepareCommand(COMMAND_BYTE_PROGRAM, address);
eepromTransmitData(Spi_tx_buf, buffer, 0, 4, size);
}
void eepromStartRead(uint8_t * buffer, size_t address, size_t size)
{
eepromPrepareCommand(COMMAND_READ_ARRAY, address);
eepromTransmitData(Spi_tx_buf, 0, buffer, 4, size);
}
void eepromBlockErase(uint32_t address)
{
eepromWriteEnable();
eepromPrepareCommand(COMMAND_BLOCK_ERASE, address);
eepromTransmitData(Spi_tx_buf, 0, 0, 4, 0);
}
// SPI i/f to EEPROM (4Mb)
// Peripheral ID 21 (0x00200000)
// Connections:
// SS PA11 (peripheral A)
// MISO PA12 (peripheral A)
// MOSI PA13 (peripheral A)
// SCK PA14 (peripheral A)
// Set clock to 3 MHz, AT25 device is rated to 70MHz, 18MHz would be better
void eepromInit()
{
Spi * spiptr = SPI;
uint32_t timer;
PMC->PMC_PCER0 |= 0x00200000L; // Enable peripheral clock to SPI
/* Configure PIO */
configure_pins(0x00007800, PIN_PERIPHERAL | PIN_INPUT | PIN_PER_A | PIN_PORTA | PIN_NO_PULLUP);
timer = (Master_frequency / 3000000) << 8; // Baud rate 3Mb/s
spiptr->SPI_MR = 0x14000011; // 0001 0100 0000 0000 0000 0000 0001 0001 Master
spiptr->SPI_CSR[0] = 0x01180009 | timer; // 0000 0001 0001 1000 xxxx xxxx 0000 1001
NVIC_EnableIRQ(SPI_IRQn);
eepromWriteEnable();
eepromWriteStatusRegister();
}
extern "C" void SPI_IRQHandler()
{
Spi * spiptr = SPI;
SPI->SPI_IDR = 0x07FF; // All interrupts off
spiptr->SPI_CR = 2; // Disable
(void) spiptr->SPI_RDR; // Dump any rx data
(void) spiptr->SPI_SR; // Clear error flags
spiptr->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS; // Stop tramsfers
Spi_complete = 1; // Indicate completion
}

View file

@ -1,44 +1,44 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void hapticOff()
{
PWM->PWM_DIS = PWM_DIS_CHID2 ; // Disable channel 2
PWM->PWM_OOV &= ~0x00040000 ; // Force low
PWM->PWM_OSS |= 0x00040000 ; // Force low
}
// pwmPercent 0-100
void hapticOn( uint32_t pwmPercent )
{
Pwm *pwmptr ;
pwmptr = PWM ;
if (pwmPercent > 100) {
pwmPercent = 100 ;
}
pwmptr->PWM_CH_NUM[2].PWM_CDTYUPD = pwmPercent ; // Duty
pwmptr->PWM_ENA = PWM_ENA_CHID2 ; // Enable channel 2
pwmptr->PWM_OSC = 0x00040000 ; // Enable output
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void hapticOff()
{
PWM->PWM_DIS = PWM_DIS_CHID2 ; // Disable channel 2
PWM->PWM_OOV &= ~0x00040000 ; // Force low
PWM->PWM_OSS |= 0x00040000 ; // Force low
}
// pwmPercent 0-100
void hapticOn( uint32_t pwmPercent )
{
Pwm *pwmptr ;
pwmptr = PWM ;
if (pwmPercent > 100) {
pwmPercent = 100 ;
}
pwmptr->PWM_CH_NUM[2].PWM_CDTYUPD = pwmPercent ; // Duty
pwmptr->PWM_ENA = PWM_ENA_CHID2 ; // Enable channel 2
pwmptr->PWM_OSC = 0x00040000 ; // Enable output
}

View file

@ -1,197 +1,197 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
// keys:
// KEY_EXIT PA31 (PC24)
// KEY_MENU PB6 (PB5)
// KEY_DOWN LCD5 PC3 (PC5)
// KEY_UP LCD6 PC2 (PC1)
// KEY_RIGHT LCD4 PC4 (PC4)
// KEY_LEFT LCD3 PC5 (PC3)
// Reqd. bit 6 LEFT, 5 RIGHT, 4 UP, 3 DOWN 2 EXIT 1 MENU
// LCD pins 5 DOWN, 4 RIGHT, 3 LEFT, 1 UP
uint32_t readKeys()
{
uint32_t x;
uint32_t result = 0;
x = lcdLock ? lcdInputs : PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP ()
x = ~x;
#if defined(REVA)
if (x & KEYS_GPIO_PIN_RIGHT)
result |= 0x02 << KEY_RIGHT;
if (x & KEYS_GPIO_PIN_LEFT)
result |= 0x02 << KEY_LEFT;
if (x & KEYS_GPIO_PIN_UP)
result |= 0x02 << KEY_UP;
if (x & KEYS_GPIO_PIN_DOWN)
result |= 0x02 << KEY_DOWN;
if (~KEYS_GPIO_REG_EXIT & KEYS_GPIO_PIN_EXIT)
result |= 0x02 << KEY_EXIT;
if (~KEYS_GPIO_REG_MENU & KEYS_GPIO_PIN_MENU)
result |= 0x02 << KEY_MENU;
#else
if (x & KEYS_GPIO_PIN_RIGHT)
result |= 0x02 << KEY_RIGHT;
if (x & KEYS_GPIO_PIN_UP)
result |= 0x02 << KEY_UP;
if (x & KEYS_GPIO_PIN_LEFT)
result |= 0x02 << KEY_LEFT;
if (x & KEYS_GPIO_PIN_DOWN)
result |= 0x02 << KEY_DOWN;
if (x & KEYS_GPIO_PIN_EXIT)
result |= 0x02 << KEY_EXIT;
if (~KEYS_GPIO_REG_MENU & KEYS_GPIO_PIN_MENU)
result |= 0x02 << KEY_MENU;
#endif
// TRACE("readKeys(): %x => %x", x, result);
return result;
}
uint32_t readTrims()
{
uint32_t result = 0;
if (~TRIMS_GPIO_REG_LHL & TRIMS_GPIO_PIN_LHL)
result |= 0x01;
if (~TRIMS_GPIO_REG_LVD & TRIMS_GPIO_PIN_LVD)
result |= 0x04;
if (~TRIMS_GPIO_REG_RVU & TRIMS_GPIO_PIN_RVU)
result |= 0x20;
if (~TRIMS_GPIO_REG_RHL & TRIMS_GPIO_PIN_RHL)
result |= 0x40;
if (~TRIMS_GPIO_REG_LHR & TRIMS_GPIO_PIN_LHR)
result |= 0x02;
if (~TRIMS_GPIO_REG_LVU & TRIMS_GPIO_PIN_LVU)
result |= 0x08;
if (~TRIMS_GPIO_REG_RVD & TRIMS_GPIO_PIN_RVD)
result |= 0x10;
if (~TRIMS_GPIO_REG_RHR & TRIMS_GPIO_PIN_RHR)
result |= 0x80;
return result;
}
uint8_t trimDown(uint8_t idx)
{
return readTrims() & (1 << idx);
}
uint8_t keyDown()
{
return readKeys() || REA_DOWN();
}
void readKeysAndTrims()
{
uint32_t i;
#if ROTARY_ENCODERS > 0
keys[BTN_REa].input(REA_DOWN());
#endif
uint8_t index = KEY_MENU;
uint8_t in = readKeys();
for (i = 1; i < 7; i++) {
keys[index].input(in & (1 << i));
++index;
}
in = readTrims();
for (i = 1; i < 256; i <<= 1) {
keys[index].input(in & i);
++index;
}
}
uint8_t keyState(uint8_t index)
{
return keys[index].state();
}
uint32_t switchState(uint8_t index)
{
uint32_t a = PIOA->PIO_PDSR;
uint32_t c = PIOC->PIO_PDSR;
uint32_t xxx = 0;
switch (index) {
#if defined(REVA)
case SW_ELE:
xxx = a & 0x00000100; // ELE_DR PA8
#else
case SW_ELE:
xxx = c & 0x80000000; // ELE_DR PC31
#endif
break;
case SW_AIL:
xxx = a & 0x00000004; // AIL-DR PA2
break;
case SW_RUD:
xxx = a & 0x00008000; // RUN_DR PA15
break;
// INP_G_ID1 INP_E_ID2
// id0 0 1
// id1 1 1
// id2 1 0
case SW_ID0:
xxx = ~c & 0x00004000; // SW_IDL1 PC14
break;
case SW_ID1:
xxx = (c & 0x00004000);
if (xxx) xxx = (c & 0x00000800);
break;
case SW_ID2:
xxx = ~c & 0x00000800; // SW_IDL2 PC11
break;
case SW_GEA:
xxx = c & 0x00010000; // SW_GEAR PC16
break;
#if defined(REVA)
case SW_THR:
xxx = a & 0x10000000; // SW_TCUT PA28
#else
case SW_THR:
xxx = c & 0x00100000; // SW_TCUT PC20
#endif
break;
case SW_TRN:
xxx = c & 0x00000100; // SW-TRAIN PC8
break;
default:
break;
}
return xxx;
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
// keys:
// KEY_EXIT PA31 (PC24)
// KEY_MENU PB6 (PB5)
// KEY_DOWN LCD5 PC3 (PC5)
// KEY_UP LCD6 PC2 (PC1)
// KEY_RIGHT LCD4 PC4 (PC4)
// KEY_LEFT LCD3 PC5 (PC3)
// Reqd. bit 6 LEFT, 5 RIGHT, 4 UP, 3 DOWN 2 EXIT 1 MENU
// LCD pins 5 DOWN, 4 RIGHT, 3 LEFT, 1 UP
uint32_t readKeys()
{
uint32_t x;
uint32_t result = 0;
x = lcdLock ? lcdInputs : PIOC->PIO_PDSR; // 6 LEFT, 5 RIGHT, 4 DOWN, 3 UP ()
x = ~x;
#if defined(REVA)
if (x & KEYS_GPIO_PIN_RIGHT)
result |= 0x02 << KEY_RIGHT;
if (x & KEYS_GPIO_PIN_LEFT)
result |= 0x02 << KEY_LEFT;
if (x & KEYS_GPIO_PIN_UP)
result |= 0x02 << KEY_UP;
if (x & KEYS_GPIO_PIN_DOWN)
result |= 0x02 << KEY_DOWN;
if (~KEYS_GPIO_REG_EXIT & KEYS_GPIO_PIN_EXIT)
result |= 0x02 << KEY_EXIT;
if (~KEYS_GPIO_REG_MENU & KEYS_GPIO_PIN_MENU)
result |= 0x02 << KEY_MENU;
#else
if (x & KEYS_GPIO_PIN_RIGHT)
result |= 0x02 << KEY_RIGHT;
if (x & KEYS_GPIO_PIN_UP)
result |= 0x02 << KEY_UP;
if (x & KEYS_GPIO_PIN_LEFT)
result |= 0x02 << KEY_LEFT;
if (x & KEYS_GPIO_PIN_DOWN)
result |= 0x02 << KEY_DOWN;
if (x & KEYS_GPIO_PIN_EXIT)
result |= 0x02 << KEY_EXIT;
if (~KEYS_GPIO_REG_MENU & KEYS_GPIO_PIN_MENU)
result |= 0x02 << KEY_MENU;
#endif
// TRACE("readKeys(): %x => %x", x, result);
return result;
}
uint32_t readTrims()
{
uint32_t result = 0;
if (~TRIMS_GPIO_REG_LHL & TRIMS_GPIO_PIN_LHL)
result |= 0x01;
if (~TRIMS_GPIO_REG_LVD & TRIMS_GPIO_PIN_LVD)
result |= 0x04;
if (~TRIMS_GPIO_REG_RVU & TRIMS_GPIO_PIN_RVU)
result |= 0x20;
if (~TRIMS_GPIO_REG_RHL & TRIMS_GPIO_PIN_RHL)
result |= 0x40;
if (~TRIMS_GPIO_REG_LHR & TRIMS_GPIO_PIN_LHR)
result |= 0x02;
if (~TRIMS_GPIO_REG_LVU & TRIMS_GPIO_PIN_LVU)
result |= 0x08;
if (~TRIMS_GPIO_REG_RVD & TRIMS_GPIO_PIN_RVD)
result |= 0x10;
if (~TRIMS_GPIO_REG_RHR & TRIMS_GPIO_PIN_RHR)
result |= 0x80;
return result;
}
uint8_t trimDown(uint8_t idx)
{
return readTrims() & (1 << idx);
}
uint8_t keyDown()
{
return readKeys() || REA_DOWN();
}
void readKeysAndTrims()
{
uint32_t i;
#if ROTARY_ENCODERS > 0
keys[BTN_REa].input(REA_DOWN());
#endif
uint8_t index = KEY_MENU;
uint8_t in = readKeys();
for (i = 1; i < 7; i++) {
keys[index].input(in & (1 << i));
++index;
}
in = readTrims();
for (i = 1; i < 256; i <<= 1) {
keys[index].input(in & i);
++index;
}
}
uint8_t keyState(uint8_t index)
{
return keys[index].state();
}
uint32_t switchState(uint8_t index)
{
uint32_t a = PIOA->PIO_PDSR;
uint32_t c = PIOC->PIO_PDSR;
uint32_t xxx = 0;
switch (index) {
#if defined(REVA)
case SW_ELE:
xxx = a & 0x00000100; // ELE_DR PA8
#else
case SW_ELE:
xxx = c & 0x80000000; // ELE_DR PC31
#endif
break;
case SW_AIL:
xxx = a & 0x00000004; // AIL-DR PA2
break;
case SW_RUD:
xxx = a & 0x00008000; // RUN_DR PA15
break;
// INP_G_ID1 INP_E_ID2
// id0 0 1
// id1 1 1
// id2 1 0
case SW_ID0:
xxx = ~c & 0x00004000; // SW_IDL1 PC14
break;
case SW_ID1:
xxx = (c & 0x00004000);
if (xxx) xxx = (c & 0x00000800);
break;
case SW_ID2:
xxx = ~c & 0x00000800; // SW_IDL2 PC11
break;
case SW_GEA:
xxx = c & 0x00010000; // SW_GEAR PC16
break;
#if defined(REVA)
case SW_THR:
xxx = a & 0x10000000; // SW_TCUT PA28
#else
case SW_THR:
xxx = c & 0x00100000; // SW_TCUT PC20
#endif
break;
case SW_TRN:
xxx = c & 0x00000100; // SW-TRAIN PC8
break;
default:
break;
}
return xxx;
}

View file

@ -1,208 +1,208 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#ifndef SIMU
extern "C" {
#include "usb/device/massstorage/MSDDriver.h"
extern unsigned char MEDSdcard_Initialize(Media *media, unsigned char mciID);
}
/** LUN read/write buffer. */
unsigned char msdBuffer[MSD_BUFFER_SIZE];
unsigned int msdReadTotal=0, msdWriteTotal=0;
static void ConfigureUsbClock(void)
{
/* Enable PLLB for USB */
PMC->CKGR_PLLBR = CKGR_PLLBR_DIVB(1)
| CKGR_PLLBR_MULB(7)
| CKGR_PLLBR_PLLBCOUNT_Msk;
while((PMC->PMC_SR & PMC_SR_LOCKB) == 0); // TODO && (timeout++ < CLOCK_TIMEOUT));
/* USB Clock uses PLLB */
PMC->PMC_USB = PMC_USB_USBDIV(1) /* /2 */
| PMC_USB_USBS; /* PLLB */
}
/** Maximum number of LUNs which can be defined. */
#define MAX_LUNS 1
/** Media index for different disks */
#define DRV_SDMMC 0 /** SD card */
Media medias[MAX_LUNS];
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
/** Device LUNs. */
MSDLun luns[MAX_LUNS];
int itoa(int val, char* buf)
{
const unsigned int radix = 10;
char* p;
unsigned int a; //every digit
int len;
char* b; //start of the digit char
char temp;
unsigned int u;
p = buf;
#if 0
if (val < 0)
{
*p++ = '-';
val = 0 - val;
}
#endif
u = (unsigned int)val;
b = p;
do
{
a = u % radix;
u /= radix;
*p++ = a + '0';
} while (u > 0);
len = (int)(p - buf);
*p-- = 0;
//swap
do
{
temp = *p;
*p = *b;
*b = temp;
--p;
++b;
} while (b < p);
return len;
}
uint8_t write_bytes(char *str, uint32_t bytes)
{
uint8_t len;
if (bytes < 1024*100) {
len = itoa(bytes / 1024, str);
str[len] = '.';
str[len+1] = '0' + ((bytes % 1024) / 103);
str[len+2] = 'K';
str[len+3] = '\0';
len += 3;
}
else if (bytes < 1024*1024) {
len = itoa(bytes / 1024, str);
str[len] = 'K';
str[len+1] = '\0';
len += 1;
}
else if (bytes < 1024*1024*100) {
len = itoa(bytes / (1024*1024), str);
str[len] = '.';
str[len+1] = '0' + ((bytes % (1024*1024)) / 104858);
str[len+2] = 'M';
str[len+3] = '\0';
len += 3;
}
else {
len = itoa(bytes / (1024*1024), str);
str[len] = 'M';
str[len+1] = '\0';
len += 1;
}
return len;
}
static void MSDCallbacks_Data( unsigned char flowDirection, unsigned int dataLength,
unsigned int fifoNullCount, unsigned int fifoFullCount )
{
if (flowDirection)
msdReadTotal += dataLength;
else
msdWriteTotal += dataLength;
strcpy(statusLineMsg, "USB Rd:");
uint8_t len = write_bytes(statusLineMsg+7, msdReadTotal);
strcpy(statusLineMsg+7+len, " Wr:");
write_bytes(statusLineMsg+7+len+4, msdWriteTotal);
showStatusLine();
}
void usbMassStorage()
{
static bool initialized = false;
if (usbPlugged() && sd_card_ready()) {
TRACE_DEBUG("usbMassStorage\n\r");
if (sdMounted()) {
Card_state = SD_ST_DATA;
audioQueue.stopSD();
logsClose();
f_mount(NULL, "", 0); // unmount SD
}
if (!initialized) {
ConfigureUsbClock();
/* Initialize LUN */
MEDSdcard_Initialize(&(medias[DRV_SDMMC]), 0);
LUN_Init(&(luns[DRV_SDMMC]), &(medias[DRV_SDMMC]),
msdBuffer, MSD_BUFFER_SIZE,
0, 0, 0, 0,
MSDCallbacks_Data);
/* BOT driver initialization */
MSDDriver_Initialize(luns, 1);
// VBus_Configure();
USBD_Connect();
initialized = true;
}
/* Mass storage state machine */
for (uint8_t i=0; i<50; i++)
MSDDriver_StateMachine();
}
else {
msdReadTotal = 0;
msdWriteTotal = 0;
}
}
#endif
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#ifndef SIMU
extern "C" {
#include "usb/device/massstorage/MSDDriver.h"
extern unsigned char MEDSdcard_Initialize(Media *media, unsigned char mciID);
}
/** LUN read/write buffer. */
unsigned char msdBuffer[MSD_BUFFER_SIZE];
unsigned int msdReadTotal=0, msdWriteTotal=0;
static void ConfigureUsbClock(void)
{
/* Enable PLLB for USB */
PMC->CKGR_PLLBR = CKGR_PLLBR_DIVB(1)
| CKGR_PLLBR_MULB(7)
| CKGR_PLLBR_PLLBCOUNT_Msk;
while((PMC->PMC_SR & PMC_SR_LOCKB) == 0); // TODO && (timeout++ < CLOCK_TIMEOUT));
/* USB Clock uses PLLB */
PMC->PMC_USB = PMC_USB_USBDIV(1) /* /2 */
| PMC_USB_USBS; /* PLLB */
}
/** Maximum number of LUNs which can be defined. */
#define MAX_LUNS 1
/** Media index for different disks */
#define DRV_SDMMC 0 /** SD card */
Media medias[MAX_LUNS];
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
/** Device LUNs. */
MSDLun luns[MAX_LUNS];
int itoa(int val, char* buf)
{
const unsigned int radix = 10;
char* p;
unsigned int a; //every digit
int len;
char* b; //start of the digit char
char temp;
unsigned int u;
p = buf;
#if 0
if (val < 0)
{
*p++ = '-';
val = 0 - val;
}
#endif
u = (unsigned int)val;
b = p;
do
{
a = u % radix;
u /= radix;
*p++ = a + '0';
} while (u > 0);
len = (int)(p - buf);
*p-- = 0;
//swap
do
{
temp = *p;
*p = *b;
*b = temp;
--p;
++b;
} while (b < p);
return len;
}
uint8_t write_bytes(char *str, uint32_t bytes)
{
uint8_t len;
if (bytes < 1024*100) {
len = itoa(bytes / 1024, str);
str[len] = '.';
str[len+1] = '0' + ((bytes % 1024) / 103);
str[len+2] = 'K';
str[len+3] = '\0';
len += 3;
}
else if (bytes < 1024*1024) {
len = itoa(bytes / 1024, str);
str[len] = 'K';
str[len+1] = '\0';
len += 1;
}
else if (bytes < 1024*1024*100) {
len = itoa(bytes / (1024*1024), str);
str[len] = '.';
str[len+1] = '0' + ((bytes % (1024*1024)) / 104858);
str[len+2] = 'M';
str[len+3] = '\0';
len += 3;
}
else {
len = itoa(bytes / (1024*1024), str);
str[len] = 'M';
str[len+1] = '\0';
len += 1;
}
return len;
}
static void MSDCallbacks_Data( unsigned char flowDirection, unsigned int dataLength,
unsigned int fifoNullCount, unsigned int fifoFullCount )
{
if (flowDirection)
msdReadTotal += dataLength;
else
msdWriteTotal += dataLength;
strcpy(statusLineMsg, "USB Rd:");
uint8_t len = write_bytes(statusLineMsg+7, msdReadTotal);
strcpy(statusLineMsg+7+len, " Wr:");
write_bytes(statusLineMsg+7+len+4, msdWriteTotal);
showStatusLine();
}
void usbMassStorage()
{
static bool initialized = false;
if (usbPlugged() && sd_card_ready()) {
TRACE_DEBUG("usbMassStorage\n\r");
if (sdMounted()) {
Card_state = SD_ST_DATA;
audioQueue.stopSD();
logsClose();
f_mount(NULL, "", 0); // unmount SD
}
if (!initialized) {
ConfigureUsbClock();
/* Initialize LUN */
MEDSdcard_Initialize(&(medias[DRV_SDMMC]), 0);
LUN_Init(&(luns[DRV_SDMMC]), &(medias[DRV_SDMMC]),
msdBuffer, MSD_BUFFER_SIZE,
0, 0, 0, 0,
MSDCallbacks_Data);
/* BOT driver initialization */
MSDDriver_Initialize(luns, 1);
// VBus_Configure();
USBD_Connect();
initialized = true;
}
/* Mass storage state machine */
for (uint8_t i=0; i<50; i++)
MSDDriver_StateMachine();
}
else {
msdReadTotal = 0;
msdWriteTotal = 0;
}
}
#endif

View file

@ -1,367 +1,367 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void setExternalModulePolarity()
{
Pwm * pwmptr = PWM;
pwmptr->PWM_CH_NUM[3].PWM_CDTYUPD = GET_PPM_DELAY(EXTERNAL_MODULE) * 2; // Duty in half uS
if (GET_PPM_POLARITY(EXTERNAL_MODULE))
pwmptr->PWM_CH_NUM[3].PWM_CMR &= ~0x00000200; // CPOL
else
pwmptr->PWM_CH_NUM[3].PWM_CMR |= 0x00000200; // CPOL
}
void setExtraModulePolarity()
{
Pwm * pwmptr = PWM;
pwmptr->PWM_CH_NUM[1].PWM_CDTYUPD = GET_PPM_DELAY(EXTRA_MODULE) * 2; // Duty in half uS
if (GET_PPM_POLARITY(EXTRA_MODULE))
pwmptr->PWM_CH_NUM[1].PWM_CMR &= ~0x00000200; // CPOL
else
pwmptr->PWM_CH_NUM[1].PWM_CMR |= 0x00000200; // CPOL
}
void module_output_active()
{
Pio *pioptr = PIOA;
pioptr->PIO_ABCDSR[0] &= ~PIO_PA17; // Peripheral C
pioptr->PIO_ABCDSR[1] |= PIO_PA17; // Peripheral C
pioptr->PIO_PDR = PIO_PA17; // Disable bit A17 Assign to peripheral
#if defined(REVX)
if (g_model.moduleData[EXTERNAL_MODULE].ppm.outputType) {
pioptr->PIO_MDDR = PIO_PA17; // Push Pull O/p in A17
}
else {
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void setExternalModulePolarity()
{
Pwm * pwmptr = PWM;
pwmptr->PWM_CH_NUM[3].PWM_CDTYUPD = GET_PPM_DELAY(EXTERNAL_MODULE) * 2; // Duty in half uS
if (GET_PPM_POLARITY(EXTERNAL_MODULE))
pwmptr->PWM_CH_NUM[3].PWM_CMR &= ~0x00000200; // CPOL
else
pwmptr->PWM_CH_NUM[3].PWM_CMR |= 0x00000200; // CPOL
}
void setExtraModulePolarity()
{
Pwm * pwmptr = PWM;
pwmptr->PWM_CH_NUM[1].PWM_CDTYUPD = GET_PPM_DELAY(EXTRA_MODULE) * 2; // Duty in half uS
if (GET_PPM_POLARITY(EXTRA_MODULE))
pwmptr->PWM_CH_NUM[1].PWM_CMR &= ~0x00000200; // CPOL
else
pwmptr->PWM_CH_NUM[1].PWM_CMR |= 0x00000200; // CPOL
}
void module_output_active()
{
Pio *pioptr = PIOA;
pioptr->PIO_ABCDSR[0] &= ~PIO_PA17; // Peripheral C
pioptr->PIO_ABCDSR[1] |= PIO_PA17; // Peripheral C
pioptr->PIO_PDR = PIO_PA17; // Disable bit A17 Assign to peripheral
#if defined(REVX)
if (g_model.moduleData[EXTERNAL_MODULE].ppm.outputType) {
pioptr->PIO_MDDR = PIO_PA17; // Push Pull O/p in A17
}
else {
pioptr->PIO_MDER = PIO_PA17; // Open Drain O/p in A17
}
#else
pioptr->PIO_MDDR = PIO_PA17; // Push Pull O/p in A17
#endif
pioptr->PIO_PUER = PIO_PA17; // With pull up
}
void init_main_ppm(uint32_t period, uint32_t out_enable)
{
Pwm * pwmptr;
setupPulsesPPMModule(EXTERNAL_MODULE);
if (out_enable) {
module_output_active();
}
pwmptr = PWM;
// PWM3 for PPM output
pwmptr->PWM_CH_NUM[3].PWM_CMR = 0x0004000B; // CLKA
pwmptr->PWM_CH_NUM[3].PWM_CPDR = period; // Period in half uS
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS
pwmptr->PWM_CH_NUM[3].PWM_CDTY = GET_PPM_DELAY(EXTERNAL_MODULE) * 2; // Duty in half uS
pwmptr->PWM_ENA = PWM_ENA_CHID3; // Enable channel 3
pwmptr->PWM_IER1 = PWM_IER1_CHID3;
setExternalModulePolarity();
NVIC_SetPriority(PWM_IRQn, 3);
NVIC_EnableIRQ(PWM_IRQn);
}
void disable_main_ppm()
{
Pio * pioptr = PIOA;
pioptr->PIO_PER = PIO_PA17; // Assign A17 to PIO
PWM->PWM_IDR1 = PWM_IDR1_CHID3;
}
void init_second_ppm(uint32_t period)
{
#if !defined(REVA)
// PWM1 for PPM2
Pwm * pwmptr = PWM;
configure_pins(PIO_PC15, PIN_PERIPHERAL | PIN_INPUT | PIN_PER_B | PIN_PORTC | PIN_NO_PULLUP);
pwmptr->PWM_CH_NUM[1].PWM_CMR = 0x0000000B; // CLKB
if (!GET_PPM_POLARITY(EXTRA_MODULE)) {
pwmptr->PWM_CH_NUM[1].PWM_CMR |= 0x00000200; // CPOL
}
pwmptr->PWM_CH_NUM[1].PWM_CPDR = period; // Period
pwmptr->PWM_CH_NUM[1].PWM_CPDRUPD = period; // Period
pwmptr->PWM_CH_NUM[1].PWM_CDTY = GET_PPM_DELAY(EXTRA_MODULE)*2; // Duty
pwmptr->PWM_CH_NUM[1].PWM_CDTYUPD = GET_PPM_DELAY(EXTRA_MODULE)*2; // Duty
pwmptr->PWM_ENA = PWM_ENA_CHID1; // Enable channel 1
pwmptr->PWM_IER1 = PWM_IER1_CHID1;
#endif
}
void disable_second_ppm()
{
#if !defined(REVA)
Pio * pioptr = PIOC;
pioptr->PIO_PER = PIO_PC15; // Assign C17 to PIO
PWM->PWM_IDR1 = PWM_IDR1_CHID1;
#endif
}
void init_no_pulses(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(3000, 0);
}
else {
// TODO
}
}
void disable_no_pulses(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
disable_ppm(EXTERNAL_MODULE);
}
else {
// TODO
}
}
void init_ppm(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(3000, 1);
}
else {
init_second_ppm(3000);
}
}
void disable_ppm(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
disable_main_ppm();
}
else {
disable_second_ppm();
}
}
// Initialise the SSC to allow PXX output.
// TD is on PA17, peripheral A
void init_ssc(uint8_t baudrateDiv1000)
{
Ssc *sscptr;
PMC->PMC_PCER0 |= 0x00400000L; // Enable peripheral clock to SSC
configure_pins(PIO_PA17, PIN_PERIPHERAL | PIN_INPUT | PIN_PER_A | PIN_PORTA);
sscptr = SSC;
sscptr->SSC_THR = 0xFF; // Make the output high.
sscptr->SSC_TFMR = 0x00000027; // 0000 0000 0000 0000 0000 0000 1010 0111 (8 bit data, lsb)
sscptr->SSC_CMR = Master_frequency / (1000 * baudrateDiv1000 * 2);
sscptr->SSC_TCMR = 0;
sscptr->SSC_CR = SSC_CR_TXEN;
#if defined(REVX)
if (IS_MODULE_MULTIMODULE(EXTERNAL_MODULE)) {
PIOA->PIO_MDDR = PIO_PA17; // Push Pull O/p in A17
} else {
PIOA->PIO_MDER = PIO_PA17; // Open Drain O/p in A17
}
#else
PIOA->PIO_MDDR = PIO_PA17; // Push Pull O/p in A17
#endif
}
void disable_ssc()
{
Pio *pioptr;
Ssc *sscptr;
// Revert back to pwm output
pioptr = PIOA;
pioptr->PIO_PER = PIO_PA17; // Assign A17 to PIO
sscptr = SSC;
sscptr->SSC_CR = SSC_CR_TXDIS;
}
void init_pxx(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(2500 * 2, 0);
init_ssc(125); // 8us per bit
}
else {
// TODO
}
}
void disable_pxx(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
disable_ssc();
disable_ppm(EXTERNAL_MODULE);
}
else {
// TODO
}
}
void init_dsm2(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(2500 * 2, 0);
init_ssc(125);
}
else {
// TODO
}
}
void disable_dsm2(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
disable_ssc();
disable_ppm(EXTERNAL_MODULE);
}
else {
// TODO
}
}
#if defined(MULTIMODULE)
void init_multimodule(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(3500 * 2, 0);
init_ssc(100);
}
else {
// TODO
}
}
void disable_multimodule(uint32_t port)
{
disable_dsm2(port);
}
#endif
#if !defined(SIMU)
extern "C" void PWM_IRQHandler(void)
{
Pwm * pwmptr = PWM;
uint32_t reason = pwmptr->PWM_ISR1;
uint32_t period;
if (reason & PWM_ISR1_CHID3) {
// Use the current protocol, don't switch until set_up_pulses
switch (s_current_protocol[EXTERNAL_MODULE]) {
case PROTO_PXX:
// Alternate periods of 6.5mS and 2.5 mS
period = pwmptr->PWM_CH_NUM[3].PWM_CPDR;
if (period == 2500 * 2) {
period = 6500 * 2;
}
else {
period = 2500 * 2;
}
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS
if (period != 2500 * 2) {
setupPulses(EXTERNAL_MODULE);
setExternalModulePolarity();
}
else {
// Kick off serial output here
Ssc * sscptr = SSC;
sscptr->SSC_TPR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].pxx.pulses);
sscptr->SSC_TCR = (uint8_t *)modulePulsesData[EXTERNAL_MODULE].pxx.ptr - (uint8_t *)modulePulsesData[EXTERNAL_MODULE].pxx.pulses;
sscptr->SSC_PTCR = SSC_PTCR_TXTEN; // Start transfers
}
break;
case PROTO_DSM2_LP45:
case PROTO_DSM2_DSM2:
case PROTO_DSM2_DSMX:
// Alternate periods of 19.5mS and 2.5 mS
period = pwmptr->PWM_CH_NUM[3].PWM_CPDR;
if (period == 2500 * 2) {
period = 19500 * 2;
}
else {
period = 2500 * 2;
}
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS
if (period != 2500 * 2) {
setupPulses(EXTERNAL_MODULE);
}
else {
// Kick off serial output here
Ssc * sscptr = SSC;
sscptr->SSC_TPR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].dsm2.pulses);
sscptr->SSC_TCR = (uint8_t *)modulePulsesData[EXTERNAL_MODULE].dsm2.ptr - (uint8_t *)modulePulsesData[EXTERNAL_MODULE].dsm2.pulses;
sscptr->SSC_PTCR = SSC_PTCR_TXTEN; // Start transfers
}
break;
#if defined(MULTIMODULE)
case PROTO_MULTIMODULE:
// Alternate periods of 5.5mS and 3.5 mS
period = pwmptr->PWM_CH_NUM[3].PWM_CPDR;
if (period == 3500 * 2) {
period = 5500 * 2;
}
else {
period = 3500 * 2;
}
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS
if (period != 3500 * 2) {
setupPulses(EXTERNAL_MODULE);
}
else {
// Kick off serial output here
Ssc * sscptr = SSC;
sscptr->SSC_TPR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].dsm2.pulses);
sscptr->SSC_TCR = (uint8_t *)modulePulsesData[EXTERNAL_MODULE].dsm2.ptr - (uint8_t *)modulePulsesData[EXTERNAL_MODULE].dsm2.pulses;
sscptr->SSC_PTCR = SSC_PTCR_TXTEN; // Start transfers
}
break;
#endif
default:
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = *modulePulsesData[EXTERNAL_MODULE].ppm.ptr++;
if (*modulePulsesData[EXTERNAL_MODULE].ppm.ptr == 0) {
setExternalModulePolarity();
setupPulses(EXTERNAL_MODULE);
}
break;
}
}
#if !defined(REVA)
if (reason & PWM_ISR1_CHID1) {
pwmptr->PWM_CH_NUM[1].PWM_CPDRUPD = *modulePulsesData[EXTRA_MODULE].ppm.ptr++;
if (*modulePulsesData[EXTRA_MODULE].ppm.ptr == 0) {
setupPulsesPPMModule(EXTRA_MODULE);
setExtraModulePolarity();
}
}
#endif
}
#endif
}
#else
pioptr->PIO_MDDR = PIO_PA17; // Push Pull O/p in A17
#endif
pioptr->PIO_PUER = PIO_PA17; // With pull up
}
void init_main_ppm(uint32_t period, uint32_t out_enable)
{
Pwm * pwmptr;
setupPulsesPPMModule(EXTERNAL_MODULE);
if (out_enable) {
module_output_active();
}
pwmptr = PWM;
// PWM3 for PPM output
pwmptr->PWM_CH_NUM[3].PWM_CMR = 0x0004000B; // CLKA
pwmptr->PWM_CH_NUM[3].PWM_CPDR = period; // Period in half uS
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS
pwmptr->PWM_CH_NUM[3].PWM_CDTY = GET_PPM_DELAY(EXTERNAL_MODULE) * 2; // Duty in half uS
pwmptr->PWM_ENA = PWM_ENA_CHID3; // Enable channel 3
pwmptr->PWM_IER1 = PWM_IER1_CHID3;
setExternalModulePolarity();
NVIC_SetPriority(PWM_IRQn, 3);
NVIC_EnableIRQ(PWM_IRQn);
}
void disable_main_ppm()
{
Pio * pioptr = PIOA;
pioptr->PIO_PER = PIO_PA17; // Assign A17 to PIO
PWM->PWM_IDR1 = PWM_IDR1_CHID3;
}
void init_second_ppm(uint32_t period)
{
#if !defined(REVA)
// PWM1 for PPM2
Pwm * pwmptr = PWM;
configure_pins(PIO_PC15, PIN_PERIPHERAL | PIN_INPUT | PIN_PER_B | PIN_PORTC | PIN_NO_PULLUP);
pwmptr->PWM_CH_NUM[1].PWM_CMR = 0x0000000B; // CLKB
if (!GET_PPM_POLARITY(EXTRA_MODULE)) {
pwmptr->PWM_CH_NUM[1].PWM_CMR |= 0x00000200; // CPOL
}
pwmptr->PWM_CH_NUM[1].PWM_CPDR = period; // Period
pwmptr->PWM_CH_NUM[1].PWM_CPDRUPD = period; // Period
pwmptr->PWM_CH_NUM[1].PWM_CDTY = GET_PPM_DELAY(EXTRA_MODULE)*2; // Duty
pwmptr->PWM_CH_NUM[1].PWM_CDTYUPD = GET_PPM_DELAY(EXTRA_MODULE)*2; // Duty
pwmptr->PWM_ENA = PWM_ENA_CHID1; // Enable channel 1
pwmptr->PWM_IER1 = PWM_IER1_CHID1;
#endif
}
void disable_second_ppm()
{
#if !defined(REVA)
Pio * pioptr = PIOC;
pioptr->PIO_PER = PIO_PC15; // Assign C17 to PIO
PWM->PWM_IDR1 = PWM_IDR1_CHID1;
#endif
}
void init_no_pulses(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(3000, 0);
}
else {
// TODO
}
}
void disable_no_pulses(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
disable_ppm(EXTERNAL_MODULE);
}
else {
// TODO
}
}
void init_ppm(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(3000, 1);
}
else {
init_second_ppm(3000);
}
}
void disable_ppm(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
disable_main_ppm();
}
else {
disable_second_ppm();
}
}
// Initialise the SSC to allow PXX output.
// TD is on PA17, peripheral A
void init_ssc(uint8_t baudrateDiv1000)
{
Ssc *sscptr;
PMC->PMC_PCER0 |= 0x00400000L; // Enable peripheral clock to SSC
configure_pins(PIO_PA17, PIN_PERIPHERAL | PIN_INPUT | PIN_PER_A | PIN_PORTA);
sscptr = SSC;
sscptr->SSC_THR = 0xFF; // Make the output high.
sscptr->SSC_TFMR = 0x00000027; // 0000 0000 0000 0000 0000 0000 1010 0111 (8 bit data, lsb)
sscptr->SSC_CMR = Master_frequency / (1000 * baudrateDiv1000 * 2);
sscptr->SSC_TCMR = 0;
sscptr->SSC_CR = SSC_CR_TXEN;
#if defined(REVX)
if (IS_MODULE_MULTIMODULE(EXTERNAL_MODULE)) {
PIOA->PIO_MDDR = PIO_PA17; // Push Pull O/p in A17
} else {
PIOA->PIO_MDER = PIO_PA17; // Open Drain O/p in A17
}
#else
PIOA->PIO_MDDR = PIO_PA17; // Push Pull O/p in A17
#endif
}
void disable_ssc()
{
Pio *pioptr;
Ssc *sscptr;
// Revert back to pwm output
pioptr = PIOA;
pioptr->PIO_PER = PIO_PA17; // Assign A17 to PIO
sscptr = SSC;
sscptr->SSC_CR = SSC_CR_TXDIS;
}
void init_pxx(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(2500 * 2, 0);
init_ssc(125); // 8us per bit
}
else {
// TODO
}
}
void disable_pxx(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
disable_ssc();
disable_ppm(EXTERNAL_MODULE);
}
else {
// TODO
}
}
void init_dsm2(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(2500 * 2, 0);
init_ssc(125);
}
else {
// TODO
}
}
void disable_dsm2(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
disable_ssc();
disable_ppm(EXTERNAL_MODULE);
}
else {
// TODO
}
}
#if defined(MULTIMODULE)
void init_multimodule(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
init_main_ppm(3500 * 2, 0);
init_ssc(100);
}
else {
// TODO
}
}
void disable_multimodule(uint32_t port)
{
disable_dsm2(port);
}
#endif
#if !defined(SIMU)
extern "C" void PWM_IRQHandler(void)
{
Pwm * pwmptr = PWM;
uint32_t reason = pwmptr->PWM_ISR1;
uint32_t period;
if (reason & PWM_ISR1_CHID3) {
// Use the current protocol, don't switch until set_up_pulses
switch (s_current_protocol[EXTERNAL_MODULE]) {
case PROTO_PXX:
// Alternate periods of 6.5mS and 2.5 mS
period = pwmptr->PWM_CH_NUM[3].PWM_CPDR;
if (period == 2500 * 2) {
period = 6500 * 2;
}
else {
period = 2500 * 2;
}
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS
if (period != 2500 * 2) {
setupPulses(EXTERNAL_MODULE);
setExternalModulePolarity();
}
else {
// Kick off serial output here
Ssc * sscptr = SSC;
sscptr->SSC_TPR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].pxx.pulses);
sscptr->SSC_TCR = (uint8_t *)modulePulsesData[EXTERNAL_MODULE].pxx.ptr - (uint8_t *)modulePulsesData[EXTERNAL_MODULE].pxx.pulses;
sscptr->SSC_PTCR = SSC_PTCR_TXTEN; // Start transfers
}
break;
case PROTO_DSM2_LP45:
case PROTO_DSM2_DSM2:
case PROTO_DSM2_DSMX:
// Alternate periods of 19.5mS and 2.5 mS
period = pwmptr->PWM_CH_NUM[3].PWM_CPDR;
if (period == 2500 * 2) {
period = 19500 * 2;
}
else {
period = 2500 * 2;
}
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS
if (period != 2500 * 2) {
setupPulses(EXTERNAL_MODULE);
}
else {
// Kick off serial output here
Ssc * sscptr = SSC;
sscptr->SSC_TPR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].dsm2.pulses);
sscptr->SSC_TCR = (uint8_t *)modulePulsesData[EXTERNAL_MODULE].dsm2.ptr - (uint8_t *)modulePulsesData[EXTERNAL_MODULE].dsm2.pulses;
sscptr->SSC_PTCR = SSC_PTCR_TXTEN; // Start transfers
}
break;
#if defined(MULTIMODULE)
case PROTO_MULTIMODULE:
// Alternate periods of 5.5mS and 3.5 mS
period = pwmptr->PWM_CH_NUM[3].PWM_CPDR;
if (period == 3500 * 2) {
period = 5500 * 2;
}
else {
period = 3500 * 2;
}
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = period; // Period in half uS
if (period != 3500 * 2) {
setupPulses(EXTERNAL_MODULE);
}
else {
// Kick off serial output here
Ssc * sscptr = SSC;
sscptr->SSC_TPR = CONVERT_PTR_UINT(modulePulsesData[EXTERNAL_MODULE].dsm2.pulses);
sscptr->SSC_TCR = (uint8_t *)modulePulsesData[EXTERNAL_MODULE].dsm2.ptr - (uint8_t *)modulePulsesData[EXTERNAL_MODULE].dsm2.pulses;
sscptr->SSC_PTCR = SSC_PTCR_TXTEN; // Start transfers
}
break;
#endif
default:
pwmptr->PWM_CH_NUM[3].PWM_CPDRUPD = *modulePulsesData[EXTERNAL_MODULE].ppm.ptr++;
if (*modulePulsesData[EXTERNAL_MODULE].ppm.ptr == 0) {
setExternalModulePolarity();
setupPulses(EXTERNAL_MODULE);
}
break;
}
}
#if !defined(REVA)
if (reason & PWM_ISR1_CHID1) {
pwmptr->PWM_CH_NUM[1].PWM_CPDRUPD = *modulePulsesData[EXTRA_MODULE].ppm.ptr++;
if (*modulePulsesData[EXTRA_MODULE].ppm.ptr == 0) {
setupPulsesPPMModule(EXTRA_MODULE);
setExtraModulePolarity();
}
}
#endif
}
#endif

View file

@ -1,47 +1,47 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint32_t pwrPressed()
{
#if defined(SIMU) || defined(REVA)
return true;
#else
return PIOC->PIO_PDSR & PIO_PC17;
#endif
}
// turn off soft power
void pwrOff()
{
#if !defined(REVA)
configure_pins(PIO_PA8, PIN_ENABLE | PIN_OUTPUT | PIN_LOW | PIN_PORTA | PIN_NO_PULLUP);
#endif
}
#if !defined(REVA)
void pwrInit()
{
// Configure RF_power (PC17)
configure_pins(PIO_PC17, PIN_ENABLE | PIN_INPUT | PIN_PORTC | PIN_NO_PULLUP | PIN_PULLDOWN);
configure_pins(PIO_PA8, PIN_ENABLE | PIN_INPUT | PIN_PORTA | PIN_PULLUP); // Enable bit A8 (Soft Power)
}
#endif
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
uint32_t pwrPressed()
{
#if defined(SIMU) || defined(REVA)
return true;
#else
return PIOC->PIO_PDSR & PIO_PC17;
#endif
}
// turn off soft power
void pwrOff()
{
#if !defined(REVA)
configure_pins(PIO_PA8, PIN_ENABLE | PIN_OUTPUT | PIN_LOW | PIN_PORTA | PIN_NO_PULLUP);
#endif
}
#if !defined(REVA)
void pwrInit()
{
// Configure RF_power (PC17)
configure_pins(PIO_PC17, PIN_ENABLE | PIN_INPUT | PIN_PORTC | PIN_NO_PULLUP | PIN_PULLDOWN);
configure_pins(PIO_PA8, PIN_ENABLE | PIN_INPUT | PIN_PORTA | PIN_PULLUP); // Enable bit A8 (Soft Power)
}
#endif

View file

@ -1,57 +1,57 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void rotencInit()
{
configure_pins( PIO_PC19 | PIO_PC21, PIN_ENABLE | PIN_INPUT | PIN_PORTC | PIN_PULLUP ) ; // 19 and 21 are rotary encoder
configure_pins( PIO_PB6, PIN_ENABLE | PIN_INPUT | PIN_PORTB | PIN_PULLUP ) ; // rotary encoder switch
PIOC->PIO_IER = PIO_PC19 | PIO_PC21 ;
NVIC_EnableIRQ(PIOC_IRQn) ;
}
void rotencEnd()
{
NVIC_DisableIRQ(PIOC_IRQn) ;
PIOC->PIO_IDR = PIO_PC19 | PIO_PC21 ;
}
volatile uint32_t Rotary_position ;
extern "C" void PIOC_IRQHandler()
{
uint32_t dummy;
dummy = PIOC->PIO_ISR ; // Read and clear status register
(void) dummy ; // Discard value - prevents compiler warning
dummy = PIOC->PIO_PDSR ; // Read Rotary encoder (PC19, PC21)
dummy >>= 19 ;
dummy &= 0x05 ; // pick out the three bits
if ( dummy != ( Rotary_position & 0x05 ) ) {
if ( ( Rotary_position & 0x01 ) ^ ( ( dummy & 0x04) >> 2 ) )
incRotaryEncoder(0, -1);
else
incRotaryEncoder(0, +1);
Rotary_position &= ~0x45 ;
Rotary_position |= dummy ;
}
}
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
void rotencInit()
{
configure_pins( PIO_PC19 | PIO_PC21, PIN_ENABLE | PIN_INPUT | PIN_PORTC | PIN_PULLUP ) ; // 19 and 21 are rotary encoder
configure_pins( PIO_PB6, PIN_ENABLE | PIN_INPUT | PIN_PORTB | PIN_PULLUP ) ; // rotary encoder switch
PIOC->PIO_IER = PIO_PC19 | PIO_PC21 ;
NVIC_EnableIRQ(PIOC_IRQn) ;
}
void rotencEnd()
{
NVIC_DisableIRQ(PIOC_IRQn) ;
PIOC->PIO_IDR = PIO_PC19 | PIO_PC21 ;
}
volatile uint32_t Rotary_position ;
extern "C" void PIOC_IRQHandler()
{
uint32_t dummy;
dummy = PIOC->PIO_ISR ; // Read and clear status register
(void) dummy ; // Discard value - prevents compiler warning
dummy = PIOC->PIO_PDSR ; // Read Rotary encoder (PC19, PC21)
dummy >>= 19 ;
dummy &= 0x05 ; // pick out the three bits
if ( dummy != ( Rotary_position & 0x05 ) ) {
if ( ( Rotary_position & 0x01 ) ^ ( ( dummy & 0x04) >> 2 ) )
incRotaryEncoder(0, -1);
else
incRotaryEncoder(0, +1);
Rotary_position &= ~0x45 ;
Rotary_position |= dummy ;
}
}

View file

@ -1,287 +1,287 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#if defined(REVX)
// TODO change this, not the right place
#define TWI_NONE 0
#define TWI_WRITE_VOL 2
#define TWI_WAIT_COMP 7
#define TWI_READ_RTC 8
#define TWI_WRITE_RTC 9
#define TWI_WAIT_RTCSTOP 10
#define TWI_WRITE_MFP 11
int8_t volumeRequired ;
int8_t Rtc_read_pending;
uint8_t Rtc_write_pending ;
int8_t Rtc_valid ;
uint8_t MFPsetting = 0 ;
uint8_t CALsetting = 0 ;
uint8_t *Twi_read_address ;
uint8_t TwiOperation ;
#define RTC_RX_BUXSIZE 10
#define RTC_SIZE 7
uint8_t Rtc_status[RTC_RX_BUXSIZE] ;
uint8_t *Rtc_write_ptr ;
uint32_t Rtc_write_count ;
uint8_t RtcConfig[8] ; // For initial config and writing to RTC
// 0x80, 0, 0, 0x08, 0, 0, 0, 0x80
uint32_t fromBCD(uint8_t bcd_value)
{
return (((bcd_value & 0xF0) * 10) >> 4) + (bcd_value & 0x0F);
}
uint32_t toBCD(uint32_t value)
{
div_t qr = div(value, 10);
return (qr.quot << 4) + qr.rem;
}
// This is called from an interrupt routine, or
// interrupts must be disabled while it is called
// from elsewhere.
void i2cCheck()
{
if ( TWI0->TWI_IMR & TWI_IMR_TXCOMP ) {
return ; // Busy
}
if ( volumeRequired >= 0 ) // Set volume to this value
{
TWI0->TWI_MMR = 0x002F0000 ; // Device 5E (>>1) and master is writing
TwiOperation = TWI_WRITE_VOL ;
TWI0->TWI_THR = volumeRequired ; // Send data
volumeRequired = -1 ;
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
else if ( Rtc_read_pending )
{
Rtc_valid = 0 ;
Rtc_read_pending = 0 ;
TWI0->TWI_MMR = 0x006F1100 ; // Device 6F and master is reading, 1 byte addr
TWI0->TWI_IADR = 0 ;
TwiOperation = TWI_READ_RTC ;
#ifndef SIMU
TWI0->TWI_RPR = (uint32_t)&Rtc_status[0] ;
#endif
TWI0->TWI_RCR = RTC_SIZE - 1 ;
if ( TWI0->TWI_SR & TWI_SR_RXRDY )
{
(void) TWI0->TWI_RHR ;
}
TWI0->TWI_PTCR = TWI_PTCR_RXTEN ; // Start transfers
TWI0->TWI_CR = TWI_CR_START ; // Start Rx
TWI0->TWI_IER = TWI_IER_RXBUFF | TWI_IER_TXCOMP ;
}
else if ( Rtc_write_pending )
{
if ( Rtc_write_pending & (2|4) )
{
TWI0->TWI_MMR = 0x006F0100 ; // Device 6F and master is writing, 1 byte addr
TwiOperation = TWI_WRITE_MFP ;
if ( Rtc_write_pending & 2 )
{
TWI0->TWI_IADR = 7 ;
TWI0->TWI_THR = MFPsetting ; // Send data
Rtc_write_pending &= ~2 ;
}
else
{
TWI0->TWI_IADR = 8 ;
TWI0->TWI_THR = CALsetting ; // Send data
Rtc_write_pending &= ~4 ;
}
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
else
{
Rtc_write_pending &= ~1 ;
TWI0->TWI_MMR = 0x006F0100 ; // Device 6F and master is writing, 1 byte addr
TWI0->TWI_IADR = 0 ;
TwiOperation = TWI_WRITE_RTC ;
#ifndef SIMU
TWI0->TWI_TPR = (uint32_t)Rtc_write_ptr+1 ;
#endif
TWI0->TWI_TCR = Rtc_write_count-1 ;
TWI0->TWI_THR = *Rtc_write_ptr ; // First byte
TWI0->TWI_PTCR = TWI_PTCR_TXTEN ; // Start data transfer
TWI0->TWI_IER = TWI_IER_TXBUFE | TWI_IER_TXCOMP ;
}
}
}
void writeRTC(uint8_t *ptr)
{
uint32_t year;
RtcConfig[0] = 0x80 | toBCD(*ptr++);
RtcConfig[1] = toBCD(*ptr++);
RtcConfig[2] = toBCD(*ptr++);
RtcConfig[3] = 0x08;
RtcConfig[4] = toBCD(*ptr++);
RtcConfig[5] = toBCD( *ptr++);
year = *ptr++;
year |= *ptr << 8;
RtcConfig[6] = toBCD(year - 2000);
RtcConfig[7] = MFPsetting;
Rtc_write_ptr = RtcConfig;
Rtc_write_count = 8;
__disable_irq();
Rtc_write_pending |= 1;
i2cCheck();
__enable_irq();
}
void readRTC()
{
Rtc_read_pending = 1 ;
__disable_irq() ;
i2cCheck() ;
__enable_irq() ;
}
// TODO should be inside an i2c_driver.cpp
#ifndef SIMU
extern "C" void TWI0_IRQHandler()
{
uint32_t status ;
status = TWI0->TWI_SR ; // Read only once, some bits cleared on read
if ( TwiOperation == TWI_READ_RTC )
{
if ( status & TWI_SR_RXBUFF )
{
TWI0->TWI_IDR = TWI_IDR_RXBUFF ;
TwiOperation = TWI_WAIT_RTCSTOP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Rx
TWI0->TWI_RCR = 1 ; // Last byte
return ;
}
else
{
// must be TXCOMP, prob. NAK in data
if ( TWI0->TWI_RCR > 0 )
{
Rtc_valid = -1 ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Rx
}
}
}
if ( TwiOperation == TWI_WAIT_RTCSTOP )
{
Rtc_valid = 1 ;
// Set the date and time
struct gtm utm;
utm.tm_sec = fromBCD( Rtc_status[0] & 0x7F ) ;
utm.tm_min = fromBCD( Rtc_status[1] & 0x7F ) ;
utm.tm_hour = fromBCD( Rtc_status[2] & 0x3F ) ;
utm.tm_mday = fromBCD( Rtc_status[4] & 0x3F ) ;
utm.tm_mon = fromBCD( Rtc_status[5] & 0x1F ) - 1;
utm.tm_year = fromBCD( Rtc_status[6] ) + 100 ;
g_rtcTime = gmktime(&utm);
TWI0->TWI_PTCR = TWI_PTCR_RXTDIS ; // Stop transfers
if ( status & TWI_SR_RXRDY )
{
(void) TWI0->TWI_RHR ; // Discard any rubbish data
}
}
if ( status & TWI_SR_NACK )
{
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
TWI0->TWI_IDR = TWI_IDR_TXCOMP | TWI_IDR_TXBUFE | TWI_IDR_RXBUFF ;
TWI0->TWI_PTCR = TWI_PTCR_TXTDIS | TWI_PTCR_RXTDIS ; // Stop transfers
if ( ( status & TWI_SR_TXCOMP ) == 0 )
{
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TwiOperation = TWI_WAIT_COMP ;
return ;
}
TwiOperation = TWI_NONE ;
i2cCheck() ;
}
#endif
#endif
struct t_i2cTime
{
uint8_t setCode ;
uint8_t Time[7] ;
} I2CTime ;
void rtcSetTime(const struct gtm * t)
{
g_ms100 = 0; // start of next second begins now
I2CTime.setCode = 0x74 ; // Tiny SET TIME CODE command
I2CTime.Time[0] = t->tm_sec ;
I2CTime.Time[1] = t->tm_min ;
I2CTime.Time[2] = t->tm_hour ;
I2CTime.Time[3] = t->tm_mday ;
I2CTime.Time[4] = t->tm_mon+1 ;
I2CTime.Time[5] = (uint8_t) (t->tm_year+TM_YEAR_BASE);
I2CTime.Time[6] = (t->tm_year+TM_YEAR_BASE) >> 8;
#if defined(REVX)
writeRTC((uint8_t *)&I2CTime.Time[0]) ;
#elif defined(COPROCESSOR)
coprocWriteData((uint8_t *) &I2CTime, 8);
#endif
}
void rtcInit()
{
#if defined(REVX)
readRTC();
#elif defined(COPROCESSOR)
coprocReadData();
#endif
}
#if defined(REVX)
void writeMFP()
{
__disable_irq();
Rtc_write_pending |= 2;
i2cCheck();
__enable_irq();
}
void setMFP()
{
MFPsetting = 0x80;
writeMFP();
}
void clearMFP()
{
MFPsetting = 0;
writeMFP();
}
#endif
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#if defined(REVX)
// TODO change this, not the right place
#define TWI_NONE 0
#define TWI_WRITE_VOL 2
#define TWI_WAIT_COMP 7
#define TWI_READ_RTC 8
#define TWI_WRITE_RTC 9
#define TWI_WAIT_RTCSTOP 10
#define TWI_WRITE_MFP 11
int8_t volumeRequired ;
int8_t Rtc_read_pending;
uint8_t Rtc_write_pending ;
int8_t Rtc_valid ;
uint8_t MFPsetting = 0 ;
uint8_t CALsetting = 0 ;
uint8_t *Twi_read_address ;
uint8_t TwiOperation ;
#define RTC_RX_BUXSIZE 10
#define RTC_SIZE 7
uint8_t Rtc_status[RTC_RX_BUXSIZE] ;
uint8_t *Rtc_write_ptr ;
uint32_t Rtc_write_count ;
uint8_t RtcConfig[8] ; // For initial config and writing to RTC
// 0x80, 0, 0, 0x08, 0, 0, 0, 0x80
uint32_t fromBCD(uint8_t bcd_value)
{
return (((bcd_value & 0xF0) * 10) >> 4) + (bcd_value & 0x0F);
}
uint32_t toBCD(uint32_t value)
{
div_t qr = div(value, 10);
return (qr.quot << 4) + qr.rem;
}
// This is called from an interrupt routine, or
// interrupts must be disabled while it is called
// from elsewhere.
void i2cCheck()
{
if ( TWI0->TWI_IMR & TWI_IMR_TXCOMP ) {
return ; // Busy
}
if ( volumeRequired >= 0 ) // Set volume to this value
{
TWI0->TWI_MMR = 0x002F0000 ; // Device 5E (>>1) and master is writing
TwiOperation = TWI_WRITE_VOL ;
TWI0->TWI_THR = volumeRequired ; // Send data
volumeRequired = -1 ;
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
else if ( Rtc_read_pending )
{
Rtc_valid = 0 ;
Rtc_read_pending = 0 ;
TWI0->TWI_MMR = 0x006F1100 ; // Device 6F and master is reading, 1 byte addr
TWI0->TWI_IADR = 0 ;
TwiOperation = TWI_READ_RTC ;
#ifndef SIMU
TWI0->TWI_RPR = (uint32_t)&Rtc_status[0] ;
#endif
TWI0->TWI_RCR = RTC_SIZE - 1 ;
if ( TWI0->TWI_SR & TWI_SR_RXRDY )
{
(void) TWI0->TWI_RHR ;
}
TWI0->TWI_PTCR = TWI_PTCR_RXTEN ; // Start transfers
TWI0->TWI_CR = TWI_CR_START ; // Start Rx
TWI0->TWI_IER = TWI_IER_RXBUFF | TWI_IER_TXCOMP ;
}
else if ( Rtc_write_pending )
{
if ( Rtc_write_pending & (2|4) )
{
TWI0->TWI_MMR = 0x006F0100 ; // Device 6F and master is writing, 1 byte addr
TwiOperation = TWI_WRITE_MFP ;
if ( Rtc_write_pending & 2 )
{
TWI0->TWI_IADR = 7 ;
TWI0->TWI_THR = MFPsetting ; // Send data
Rtc_write_pending &= ~2 ;
}
else
{
TWI0->TWI_IADR = 8 ;
TWI0->TWI_THR = CALsetting ; // Send data
Rtc_write_pending &= ~4 ;
}
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
else
{
Rtc_write_pending &= ~1 ;
TWI0->TWI_MMR = 0x006F0100 ; // Device 6F and master is writing, 1 byte addr
TWI0->TWI_IADR = 0 ;
TwiOperation = TWI_WRITE_RTC ;
#ifndef SIMU
TWI0->TWI_TPR = (uint32_t)Rtc_write_ptr+1 ;
#endif
TWI0->TWI_TCR = Rtc_write_count-1 ;
TWI0->TWI_THR = *Rtc_write_ptr ; // First byte
TWI0->TWI_PTCR = TWI_PTCR_TXTEN ; // Start data transfer
TWI0->TWI_IER = TWI_IER_TXBUFE | TWI_IER_TXCOMP ;
}
}
}
void writeRTC(uint8_t *ptr)
{
uint32_t year;
RtcConfig[0] = 0x80 | toBCD(*ptr++);
RtcConfig[1] = toBCD(*ptr++);
RtcConfig[2] = toBCD(*ptr++);
RtcConfig[3] = 0x08;
RtcConfig[4] = toBCD(*ptr++);
RtcConfig[5] = toBCD( *ptr++);
year = *ptr++;
year |= *ptr << 8;
RtcConfig[6] = toBCD(year - 2000);
RtcConfig[7] = MFPsetting;
Rtc_write_ptr = RtcConfig;
Rtc_write_count = 8;
__disable_irq();
Rtc_write_pending |= 1;
i2cCheck();
__enable_irq();
}
void readRTC()
{
Rtc_read_pending = 1 ;
__disable_irq() ;
i2cCheck() ;
__enable_irq() ;
}
// TODO should be inside an i2c_driver.cpp
#ifndef SIMU
extern "C" void TWI0_IRQHandler()
{
uint32_t status ;
status = TWI0->TWI_SR ; // Read only once, some bits cleared on read
if ( TwiOperation == TWI_READ_RTC )
{
if ( status & TWI_SR_RXBUFF )
{
TWI0->TWI_IDR = TWI_IDR_RXBUFF ;
TwiOperation = TWI_WAIT_RTCSTOP ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Rx
TWI0->TWI_RCR = 1 ; // Last byte
return ;
}
else
{
// must be TXCOMP, prob. NAK in data
if ( TWI0->TWI_RCR > 0 )
{
Rtc_valid = -1 ;
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Rx
}
}
}
if ( TwiOperation == TWI_WAIT_RTCSTOP )
{
Rtc_valid = 1 ;
// Set the date and time
struct gtm utm;
utm.tm_sec = fromBCD( Rtc_status[0] & 0x7F ) ;
utm.tm_min = fromBCD( Rtc_status[1] & 0x7F ) ;
utm.tm_hour = fromBCD( Rtc_status[2] & 0x3F ) ;
utm.tm_mday = fromBCD( Rtc_status[4] & 0x3F ) ;
utm.tm_mon = fromBCD( Rtc_status[5] & 0x1F ) - 1;
utm.tm_year = fromBCD( Rtc_status[6] ) + 100 ;
g_rtcTime = gmktime(&utm);
TWI0->TWI_PTCR = TWI_PTCR_RXTDIS ; // Stop transfers
if ( status & TWI_SR_RXRDY )
{
(void) TWI0->TWI_RHR ; // Discard any rubbish data
}
}
if ( status & TWI_SR_NACK )
{
TWI0->TWI_CR = TWI_CR_STOP ; // Stop Tx
}
TWI0->TWI_IDR = TWI_IDR_TXCOMP | TWI_IDR_TXBUFE | TWI_IDR_RXBUFF ;
TWI0->TWI_PTCR = TWI_PTCR_TXTDIS | TWI_PTCR_RXTDIS ; // Stop transfers
if ( ( status & TWI_SR_TXCOMP ) == 0 )
{
TWI0->TWI_IER = TWI_IER_TXCOMP ;
TwiOperation = TWI_WAIT_COMP ;
return ;
}
TwiOperation = TWI_NONE ;
i2cCheck() ;
}
#endif
#endif
struct t_i2cTime
{
uint8_t setCode ;
uint8_t Time[7] ;
} I2CTime ;
void rtcSetTime(const struct gtm * t)
{
g_ms100 = 0; // start of next second begins now
I2CTime.setCode = 0x74 ; // Tiny SET TIME CODE command
I2CTime.Time[0] = t->tm_sec ;
I2CTime.Time[1] = t->tm_min ;
I2CTime.Time[2] = t->tm_hour ;
I2CTime.Time[3] = t->tm_mday ;
I2CTime.Time[4] = t->tm_mon+1 ;
I2CTime.Time[5] = (uint8_t) (t->tm_year+TM_YEAR_BASE);
I2CTime.Time[6] = (t->tm_year+TM_YEAR_BASE) >> 8;
#if defined(REVX)
writeRTC((uint8_t *)&I2CTime.Time[0]) ;
#elif defined(COPROCESSOR)
coprocWriteData((uint8_t *) &I2CTime, 8);
#endif
}
void rtcInit()
{
#if defined(REVX)
readRTC();
#elif defined(COPROCESSOR)
coprocReadData();
#endif
}
#if defined(REVX)
void writeMFP()
{
__disable_irq();
Rtc_write_pending |= 2;
i2cCheck();
__enable_irq();
}
void setMFP()
{
MFPsetting = 0x80;
writeMFP();
}
void clearMFP()
{
MFPsetting = 0;
writeMFP();
}
#endif

View file

@ -1,150 +1,150 @@
/****************************************************************************
* Copyright (c) 2011 by Michael Fischer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*****************************************************************************
* History:
*
* 22.05.2011 mifi First Version
****************************************************************************/
/*
* In this linker script there is no heap available.
* The stack start at the end of the ram segment.
*/
/*
* Take a look in the "The GNU linker" manual, here you get
* the following information about the "MEMORY":
*
* "The MEMORY command describes the location and size of
* blocks of memory in the target."
*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x00400000, LENGTH = 128K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
/*
* And the "SECTION" is used for:
*
* "The SECTIONS command tells the linker how to map input
* sections into output sections, and how to place the output
* sections in memory.
*/
SECTIONS
{
/*
* The ".text" section is used for the code, and
* read only (.rodata) data. Even the vectors (.vectors)
* MUST be saved at the start of this section.
*/
.text :
{
_stext = .; /* Provide the name for the start of this section */
CREATE_OBJECT_SYMBOLS
KEEP(*(.vectors))
*(.text)
*(.text.*)
. = ALIGN(4); /* Align the start of the exidx part */
*(.ARM.exidx)
*(.ARM.exidx.*)
. = ALIGN(4); /* Align the start of the rodata part */
*(.rodata)
*(.rodata.*)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4); /* Align the end of the section */
} > FLASH = 0
_etext = .; /* Provide the name for the end of this section */
/*
* The ".data" section is used for initialized data
* and for functions (.fastrun) which should be copied
* from flash to ram. This functions will later be
* executed from ram instead of flash.
*/
.data : AT (_etext)
{
. = ALIGN(4); /* Align the start of the section */
_sdata = .; /* Provide the name for the start of this section */
*(.data)
*(.data.*)
. = ALIGN(4); /* Align the start of the fastrun part */
*(.fastrun)
*(.fastrun.*)
. = ALIGN(4); /* Align the end of the section */
} > RAM
_edata = .; /* Provide the name for the end of this section */
/*
* The ".bss" section is used for uninitialized data.
* This section will be cleared by the startup code.
*/
.bss :
{
. = ALIGN(4); /* Align the start of the section */
_sbss = .; /* Provide the name for the start of this section */
*(.bss)
*(.bss.*)
. = ALIGN(4); /* Align the end of the section */
} > RAM
_ebss = .; /* Provide the name for the end of this section */
. = ALIGN(4); /* Align the end of the section */
__end = .;
_end = .;
/*
* The ".stack" section is our stack.
* Here this section starts at the end of the ram segment.
*/
_estack = ORIGIN(RAM) + LENGTH(RAM);
}
/*** EOF **/
/****************************************************************************
* Copyright (c) 2011 by Michael Fischer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*****************************************************************************
* History:
*
* 22.05.2011 mifi First Version
****************************************************************************/
/*
* In this linker script there is no heap available.
* The stack start at the end of the ram segment.
*/
/*
* Take a look in the "The GNU linker" manual, here you get
* the following information about the "MEMORY":
*
* "The MEMORY command describes the location and size of
* blocks of memory in the target."
*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x00400000, LENGTH = 128K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
/*
* And the "SECTION" is used for:
*
* "The SECTIONS command tells the linker how to map input
* sections into output sections, and how to place the output
* sections in memory.
*/
SECTIONS
{
/*
* The ".text" section is used for the code, and
* read only (.rodata) data. Even the vectors (.vectors)
* MUST be saved at the start of this section.
*/
.text :
{
_stext = .; /* Provide the name for the start of this section */
CREATE_OBJECT_SYMBOLS
KEEP(*(.vectors))
*(.text)
*(.text.*)
. = ALIGN(4); /* Align the start of the exidx part */
*(.ARM.exidx)
*(.ARM.exidx.*)
. = ALIGN(4); /* Align the start of the rodata part */
*(.rodata)
*(.rodata.*)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4); /* Align the end of the section */
} > FLASH = 0
_etext = .; /* Provide the name for the end of this section */
/*
* The ".data" section is used for initialized data
* and for functions (.fastrun) which should be copied
* from flash to ram. This functions will later be
* executed from ram instead of flash.
*/
.data : AT (_etext)
{
. = ALIGN(4); /* Align the start of the section */
_sdata = .; /* Provide the name for the start of this section */
*(.data)
*(.data.*)
. = ALIGN(4); /* Align the start of the fastrun part */
*(.fastrun)
*(.fastrun.*)
. = ALIGN(4); /* Align the end of the section */
} > RAM
_edata = .; /* Provide the name for the end of this section */
/*
* The ".bss" section is used for uninitialized data.
* This section will be cleared by the startup code.
*/
.bss :
{
. = ALIGN(4); /* Align the start of the section */
_sbss = .; /* Provide the name for the start of this section */
*(.bss)
*(.bss.*)
. = ALIGN(4); /* Align the end of the section */
} > RAM
_ebss = .; /* Provide the name for the end of this section */
. = ALIGN(4); /* Align the end of the section */
__end = .;
_end = .;
/*
* The ".stack" section is our stack.
* Here this section starts at the end of the ram segment.
*/
_estack = ORIGIN(RAM) + LENGTH(RAM);
}
/*** EOF **/

Some files were not shown because too many files have changed in this diff Show more