Initial import
This commit is contained in:
commit
dee9335db4
36 changed files with 3901 additions and 0 deletions
4
.gdbinit
Normal file
4
.gdbinit
Normal file
|
@ -0,0 +1,4 @@
|
|||
tar rem:3333
|
||||
file image.elf
|
||||
foc c
|
||||
|
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
*.o
|
||||
*.bin
|
||||
test/test
|
||||
test/test.bin
|
||||
tags
|
||||
core
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "lib/unicore-mx"]
|
||||
path = lib/unicore-mx
|
||||
url = https://gitlab.com/insane-adding-machines/unicore-mx
|
339
LICENSE
Normal file
339
LICENSE
Normal file
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
55
Makefile
Normal file
55
Makefile
Normal file
|
@ -0,0 +1,55 @@
|
|||
CROSS_COMPILE:=arm-none-eabi-
|
||||
CC:=$(CROSS_COMPILE)gcc
|
||||
LD:=$(CROSS_COMPILE)gcc
|
||||
USECFS:=$(HOME)/src/usecfs
|
||||
WOLFSSL:=$(HOME)/src/wolfssl
|
||||
|
||||
OBJS:=startup.o main.o system.o $(USECFS)/src/usecfs_dev_spi.o $(USECFS)/src/usecfs.o mem.o led.o \
|
||||
i2c.o display.o font_twisted.o spi.o spi_flash.o button.o systick.o newlib.o uart.o ui.o \
|
||||
sdcard.o random.o
|
||||
OBJS+= \
|
||||
$(WOLFSSL)/wolfcrypt/src/sha256.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/chacha.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/pwdbased.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/hash.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/hmac.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/sp_int.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/sp_cortexm.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/wolfmath.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/memory.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/random.o \
|
||||
$(WOLFSSL)/wolfcrypt/src/wc_port.o
|
||||
|
||||
|
||||
UMX:=lib/unicore-mx/lib/libucmx_stm32f4.a
|
||||
UMXFLAGS:=-Ilib/unicore-mx/include/ -DSTM32F4
|
||||
LIBS+=$(UMX)
|
||||
|
||||
|
||||
LSCRIPT:=target.ld
|
||||
|
||||
OBJCOPY:=$(CROSS_COMPILE)objcopy
|
||||
|
||||
CFLAGS:=-mcpu=cortex-m3 -mthumb -Wall -Wno-main -Wstack-usage=200 -ffreestanding -Wno-unused -DBLOCK_SIZE=512 -I$(USECFS)/src -I. -I$(WOLFSSL) -Ilib/unicore-mx/include
|
||||
CFLAGS+=-specs=nano.specs -lc -lg
|
||||
CFLAGS+=$(UMXFLAGS)
|
||||
#CFLAGS+=-O2
|
||||
CFLAGS+=-g -ggdb3
|
||||
|
||||
CFLAGS+=-DWOLFSSL_USER_SETTINGS -DCRYPTO
|
||||
|
||||
LDFLAGS:=-T $(LSCRIPT) -Wl,-gc-sections -Wl,-Map=image.map -mcpu=cortex-m3 -mthumb -nostartfiles
|
||||
|
||||
#all: image.bin
|
||||
|
||||
image.bin: image.elf
|
||||
$(OBJCOPY) -O binary $^ $@
|
||||
|
||||
image.elf: $(LIBS) $(OBJS) $(LSCRIPT)
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
|
||||
|
||||
$(UMX):
|
||||
make -C lib/unicore-mx FP_FLAGS="-O3 -mfloat-abi=soft" TARGETS=stm32/f4
|
||||
|
||||
clean:
|
||||
rm -f image.bin image.elf *.o image.map $(WOLFSSL)/wolfcrypt/src/*.o $(USECFS)/src/*.o
|
229
button.c
Normal file
229
button.c
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "system.h"
|
||||
#include "button.h"
|
||||
#include "systick.h"
|
||||
#include "unicore-mx/stm32/gpio.h"
|
||||
#include "unicore-mx/stm32/exti.h"
|
||||
#include "unicore-mx/stm32/rcc.h"
|
||||
#include "unicore-mx/stm32/f4/rcc.h"
|
||||
#include "unicore-mx/stm32/adc.h"
|
||||
#include "unicore-mx/stm32/f4/adc.h"
|
||||
#include "unicore-mx/stm32/f4/nvic.h"
|
||||
|
||||
#define BUTTON_DEBOUNCE_TIME 50
|
||||
#define BUTTON_HOLD_TIME 1500
|
||||
|
||||
/* Selectors: PC4, PC5, PC6 */
|
||||
|
||||
#define PSEL_0 (1 << 5)
|
||||
#define PSEL_1 (1 << 4)
|
||||
#define PSEL_2 (1 << 6)
|
||||
|
||||
|
||||
/* Input lines: PB12, PB13, PB14, PB15 */
|
||||
|
||||
#define PLINE_0 (1 << 12)
|
||||
#define PLINE_1 (1 << 13)
|
||||
#define PLINE_2 (1 << 14)
|
||||
#define PLINE_3 (1 << 15)
|
||||
|
||||
#define PSEL_MASK (PSEL_0 | PSEL_1 | PSEL_2)
|
||||
#define PLINE_MASK (PLINE_0 | PLINE_1 | PLINE_2 | PLINE_3)
|
||||
|
||||
enum button_state {
|
||||
IDLE = 0,
|
||||
PRESSING,
|
||||
PRESSED,
|
||||
HOLD,
|
||||
RELEASING,
|
||||
};
|
||||
|
||||
static volatile int button_current_latch = 0;
|
||||
static uint32_t button_latch_switchtime;
|
||||
static volatile int button_press_pending = 0;
|
||||
|
||||
static void input_run(uint32_t ev, void *arg);
|
||||
static void input_init(void);
|
||||
|
||||
const char button_task_name[] = "Input";
|
||||
|
||||
|
||||
static void button_setup(void)
|
||||
{
|
||||
int i;
|
||||
uint32_t exti_irq;
|
||||
rcc_periph_clock_enable(RCC_SYSCFG);
|
||||
rcc_periph_clock_enable(RCC_GPIOC);
|
||||
rcc_periph_clock_enable(RCC_GPIOB);
|
||||
|
||||
gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, PSEL_MASK);
|
||||
gpio_clear(GPIOC, PSEL_MASK);
|
||||
|
||||
gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, PLINE_MASK);
|
||||
|
||||
nvic_enable_irq(NVIC_EXTI15_10_IRQ);
|
||||
nvic_set_priority(NVIC_EXTI15_10_IRQ, 1);
|
||||
|
||||
exti_select_source(PLINE_0, GPIOB);
|
||||
exti_select_source(PLINE_1, GPIOB);
|
||||
exti_select_source(PLINE_2, GPIOB);
|
||||
exti_select_source(PLINE_3, GPIOB);
|
||||
}
|
||||
|
||||
static void button_start_read(void)
|
||||
{
|
||||
exti_set_trigger(PLINE_MASK, EXTI_TRIGGER_RISING);
|
||||
exti_enable_request(PLINE_0);
|
||||
exti_enable_request(PLINE_1);
|
||||
exti_enable_request(PLINE_2);
|
||||
exti_enable_request(PLINE_3);
|
||||
}
|
||||
|
||||
void isr_exti(void)
|
||||
{
|
||||
button_press_pending = (GPIO_ODR(GPIOC) & PSEL_MASK);
|
||||
exti_reset_request(PLINE_0);
|
||||
exti_reset_request(PLINE_1);
|
||||
exti_reset_request(PLINE_2);
|
||||
exti_reset_request(PLINE_3);
|
||||
}
|
||||
|
||||
/* Button interface */
|
||||
struct user_button
|
||||
{
|
||||
enum button_state state;
|
||||
uint32_t transition_start_timestamp;
|
||||
};
|
||||
|
||||
static struct user_button Buttons[N_BUTTONS];
|
||||
|
||||
int button_poll(void (*callback)(uint8_t press, int hold))
|
||||
{
|
||||
if (button_press_pending) {
|
||||
volatile uint32_t line_status = (gpio_get(GPIOB, PLINE_MASK));
|
||||
volatile uint32_t latch_status = button_press_pending;
|
||||
int i;
|
||||
if (line_status) {
|
||||
int b = -1;
|
||||
int latch = -1;
|
||||
if (latch_status & PSEL_0)
|
||||
latch = 0;
|
||||
else if (latch_status & PSEL_1)
|
||||
latch = 1;
|
||||
else if (latch_status & PSEL_2)
|
||||
latch = 2;
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
if (latch != button_current_latch)
|
||||
return 0;
|
||||
if (line_status & PLINE_0)
|
||||
b = 0;
|
||||
else if (line_status & PLINE_1)
|
||||
b = 1;
|
||||
else if (line_status & PLINE_2)
|
||||
b = 2;
|
||||
else if (line_status & PLINE_3)
|
||||
b = 3;
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
b += latch * 4;
|
||||
|
||||
if((Buttons[b].state == IDLE) || (Buttons[b].state == RELEASING)) {
|
||||
Buttons[b].state = PRESSING;
|
||||
Buttons[b].transition_start_timestamp = jiffies;
|
||||
printf("%06u: ST: PRESSING\r\n", jiffies);
|
||||
button_press_pending = 0;
|
||||
return 0;
|
||||
} else {
|
||||
uint32_t p_interval = jiffies - Buttons[b].transition_start_timestamp;
|
||||
if (p_interval > BUTTON_HOLD_TIME) {
|
||||
if (Buttons[b].state < HOLD) {
|
||||
callback(b, 1);
|
||||
Buttons[b].state = HOLD;
|
||||
Buttons[b].transition_start_timestamp = jiffies;
|
||||
button_press_pending = 0;
|
||||
printf("%06u: ST: HOLD\r\n", jiffies);
|
||||
}
|
||||
} else if (p_interval > BUTTON_DEBOUNCE_TIME) {
|
||||
if (Buttons[b].state == PRESSING) {
|
||||
callback(b, 0);
|
||||
Buttons[b].state = PRESSED;
|
||||
printf("%06u: ST: PRESSED\r\n", jiffies);
|
||||
button_press_pending = 0;
|
||||
}
|
||||
if (Buttons[b].state == HOLD) {
|
||||
callback(b, 1);
|
||||
Buttons[b].transition_start_timestamp = jiffies;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
int base = button_current_latch * 4;
|
||||
int i;
|
||||
for (i = base; i < base + 4; i++)
|
||||
{
|
||||
if (Buttons[i].state == RELEASING) {
|
||||
if ((jiffies - Buttons[i].transition_start_timestamp) > (BUTTON_DEBOUNCE_TIME)) {
|
||||
Buttons[i].state = IDLE;
|
||||
Buttons[i].transition_start_timestamp = 0;
|
||||
printf("%06u: ST: IDLE\r\n", jiffies);
|
||||
}
|
||||
} else if (Buttons[i].state != IDLE) {
|
||||
Buttons[i].state = RELEASING;
|
||||
Buttons[i].transition_start_timestamp = jiffies;
|
||||
printf("%06u: ST:0\r\n", jiffies);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jiffies >= button_latch_switchtime) {
|
||||
uint32_t latch = button_current_latch + 1;
|
||||
uint32_t selected_pin = PSEL_0;
|
||||
gpio_clear(GPIOC, PSEL_0);
|
||||
gpio_clear(GPIOC, PSEL_1);
|
||||
gpio_clear(GPIOC, PSEL_2);
|
||||
switch(latch){
|
||||
case 1:
|
||||
selected_pin = PSEL_1;
|
||||
break;
|
||||
case 2:
|
||||
selected_pin = PSEL_2;
|
||||
break;
|
||||
case 3:
|
||||
latch = 0;
|
||||
selected_pin = PSEL_0;
|
||||
break;
|
||||
default:
|
||||
latch = 0;
|
||||
}
|
||||
asm volatile("cpsid i");
|
||||
gpio_set(GPIOC, selected_pin);
|
||||
button_current_latch = latch;
|
||||
while ((GPIO_ODR(GPIOC) & PSEL_MASK) != selected_pin)
|
||||
;
|
||||
asm volatile("cpsie i");
|
||||
button_latch_switchtime = jiffies + 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void button_init(void)
|
||||
{
|
||||
memset(Buttons, 0, sizeof(struct user_button) * N_BUTTONS);
|
||||
button_setup();
|
||||
button_start_read();
|
||||
}
|
||||
|
||||
|
53
button.h
Normal file
53
button.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef BUTTON_H_INCLUDED
|
||||
#define BUTTON_H_INCLUDED
|
||||
|
||||
|
||||
void button_init(void);
|
||||
int button_poll(void (*callback)(uint8_t press, int hold));
|
||||
int input_get_swr(void);
|
||||
|
||||
#define N_BUTTONS 12
|
||||
#define BUTTON_0 4
|
||||
#define BUTTON_1 5
|
||||
#define BUTTON_2 6
|
||||
#define BUTTON_3 7
|
||||
#define BUTTON_4 0
|
||||
#define BUTTON_5 1
|
||||
#define BUTTON_6 2
|
||||
#define BUTTON_7 8
|
||||
#define BUTTON_8 9
|
||||
#define BUTTON_9 10
|
||||
#define BUTTON_SCROLL 11
|
||||
#define BUTTON_ENTER 3
|
||||
|
||||
static inline char bu2c(uint8_t btn)
|
||||
{
|
||||
switch(btn) {
|
||||
case BUTTON_0:
|
||||
return '0';
|
||||
case BUTTON_1:
|
||||
return '1';
|
||||
case BUTTON_2:
|
||||
return '2';
|
||||
case BUTTON_3:
|
||||
return '3';
|
||||
case BUTTON_4:
|
||||
return '4';
|
||||
case BUTTON_5:
|
||||
return '5';
|
||||
case BUTTON_6:
|
||||
return '6';
|
||||
case BUTTON_7:
|
||||
return '7';
|
||||
case BUTTON_8:
|
||||
return '8';
|
||||
case BUTTON_9:
|
||||
return '9';
|
||||
case BUTTON_SCROLL:
|
||||
return ' ';
|
||||
case BUTTON_ENTER:
|
||||
return '\r';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
102
display.c
Normal file
102
display.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "display.h"
|
||||
#include "systick.h"
|
||||
#include "system.h"
|
||||
|
||||
|
||||
static uint8_t contrast = 0xcf;
|
||||
|
||||
|
||||
void display_scroll(void *priv, uint8_t line)
|
||||
{
|
||||
display_send_cmd1(priv, SSD1306_SETSTARTLINE, (line % 0x40) + 0x40);
|
||||
}
|
||||
|
||||
void display_setcontrast(void *priv, uint8_t c)
|
||||
{
|
||||
contrast = c;
|
||||
display_send_cmd1(priv, SSD1306_SETCONTRAST, contrast);
|
||||
}
|
||||
|
||||
uint8_t display_getcontrast(void *priv)
|
||||
{
|
||||
return contrast;
|
||||
}
|
||||
|
||||
void display_clear(void *priv)
|
||||
{
|
||||
|
||||
int i,j;
|
||||
uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
display_send_cmd(NULL, 0x00);
|
||||
display_send_cmd(NULL, 0x10);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
display_send_cmd2(NULL, SSD1306_PAGEADDR, i, 0xFF);
|
||||
for (j = 0; j < WIDTH; j++)
|
||||
display_send_data(NULL, zeros, 8);
|
||||
}
|
||||
}
|
||||
|
||||
void display_text(int row, const char *text)
|
||||
{
|
||||
int k;
|
||||
display_send_cmd(NULL, 0x00);
|
||||
display_send_cmd(NULL, 0x10);
|
||||
display_send_cmd2(NULL, SSD1306_PAGEADDR, 7 - row, 0xFF);
|
||||
for(k = 0; k < strlen(text); k++)
|
||||
display_send_data(NULL, fb_font[text[k]], 8);
|
||||
}
|
||||
|
||||
int display_init(void *priv)
|
||||
{
|
||||
int i;
|
||||
int k = 0;
|
||||
int row = 0;
|
||||
volatile int j;
|
||||
uint8_t dbuf2[64] = {};
|
||||
int page = 0;
|
||||
int seg = 0;
|
||||
volatile uint32_t now;
|
||||
|
||||
|
||||
for (i = 1; i < 65; i++) {
|
||||
dbuf2[i] = 0;
|
||||
}
|
||||
display_send_cmd(priv, SSD1306_DISPLAYOFF);
|
||||
display_send_cmd1(priv, 0xD6, 0x01);
|
||||
display_send_cmd(priv, 0xA1);
|
||||
display_setcontrast(priv, contrast);
|
||||
display_send_cmd1(priv, SSD1306_CHARGEPUMP, 0x14);
|
||||
display_send_cmd1(priv, SSD1306_MEMORYMODE, 0x00);
|
||||
display_send_cmd1(priv, SSD1306_SETCOMPINS, 0x12);
|
||||
display_send_cmd1(priv, SSD1306_SETDISPLAYOFFSET, 0x00);
|
||||
display_send_cmd1(priv, SSD1306_SETVCOMDETECT, 0x00);
|
||||
display_send_cmd1(priv, SSD1306_SETMULTIPLEX, 63);
|
||||
display_send_cmd(priv, SSD1306_COMSCANINC);
|
||||
display_send_cmd(priv, SSD1306_DISPLAYALLON_RESUME);
|
||||
display_send_cmd(priv, SSD1306_DISPLAYON);
|
||||
display_send_cmd(priv, 0x2E);
|
||||
|
||||
display_send_cmd2(priv, SSD1306_PAGEADDR, 0, 0xFF);
|
||||
display_send_cmd2(priv, SSD1306_COLUMNADDR, 0, WIDTH - 1);
|
||||
display_send_cmd1(priv, SSD1306_SETSTARTLINE, 0);
|
||||
display_send_cmd(priv, 0x00);
|
||||
display_send_cmd(priv, 0x10);
|
||||
for (page = 0; page < 8; page++) {
|
||||
display_send_cmd2(priv, SSD1306_PAGEADDR, page, 0xFF);
|
||||
for (seg= 0; seg < 32; seg++) {
|
||||
display_send_data(priv, dbuf2, 8);
|
||||
}
|
||||
display_send_cmd1(priv, SSD1306_SETSTARTLINE, row);
|
||||
}
|
||||
return 0;
|
||||
}
|
55
display.h
Normal file
55
display.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#ifndef DISPLAY_H_INCLUDED
|
||||
#define DISPLAY_H_INCLUDED
|
||||
#include <stdint.h>
|
||||
|
||||
#define WIDTH 128
|
||||
#define PIXEL_HEIGHT 64
|
||||
#define HEIGHT (PIXEL_HEIGHT / 8)
|
||||
extern const unsigned char fb_font[256][8];
|
||||
#define SSD1306_MEMORYMODE 0x20
|
||||
#define SSD1306_COLUMNADDR 0x21
|
||||
#define SSD1306_PAGEADDR 0x22
|
||||
#define SSD1306_SETCONTRAST 0x81
|
||||
#define SSD1306_CHARGEPUMP 0x8D
|
||||
#define SSD1306_SEGREMAP 0xA0
|
||||
#define SSD1306_DISPLAYALLON_RESUME 0xA4
|
||||
#define SSD1306_DISPLAYALLON 0xA5
|
||||
#define SSD1306_NORMALDISPLAY 0xA6
|
||||
#define SSD1306_INVERTDISPLAY 0xA7
|
||||
#define SSD1306_SETMULTIPLEX 0xA8
|
||||
#define SSD1306_DISPLAYOFF 0xAE
|
||||
#define SSD1306_DISPLAYON 0xAF
|
||||
#define SSD1306_COMSCANINC 0xC0
|
||||
#define SSD1306_COMSCANDEC 0xC8
|
||||
#define SSD1306_SETDISPLAYOFFSET 0xD3
|
||||
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5
|
||||
#define SSD1306_SETPRECHARGE 0xD9
|
||||
#define SSD1306_SETCOMPINS 0xDA
|
||||
#define SSD1306_SETVCOMDETECT 0xDB
|
||||
#define SSD1306_SETLOWCOLUMN 0x00
|
||||
#define SSD1306_SETHIGHCOLUMN 0x10
|
||||
#define SSD1306_SETSTARTLINE 0x40
|
||||
#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26
|
||||
#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27
|
||||
#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
|
||||
#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A
|
||||
#define SSD1306_DEACTIVATE_SCROLL 0x2E
|
||||
#define SSD1306_ACTIVATE_SCROLL 0x2F
|
||||
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3
|
||||
|
||||
|
||||
|
||||
/* driver module plug-in (SPI or I2C) */
|
||||
void display_send_data(void *priv, const uint8_t *buf, int len);
|
||||
void display_send_cmd(void *priv, uint8_t cmd);
|
||||
void display_send_cmd1(void *priv, uint8_t cmd, uint8_t arg1);
|
||||
void display_send_cmd2(void *priv, uint8_t cmd, uint8_t arg1, uint8_t arg2);
|
||||
|
||||
int display_init(void *priv);
|
||||
void display_text(int row, const char *text);
|
||||
void display_scroll(void *priv, uint8_t line);
|
||||
void display_setcontrast(void *priv, uint8_t c);
|
||||
uint8_t display_getcontrast(void *priv);
|
||||
void display_clear(void *priv);
|
||||
|
||||
#endif
|
BIN
font_twisted.c
Normal file
BIN
font_twisted.c
Normal file
Binary file not shown.
235
i2c.c
Normal file
235
i2c.c
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "system.h"
|
||||
#include "i2c.h"
|
||||
#include "display.h"
|
||||
#define DISPLAY_I2C_ADDR 0x3C
|
||||
|
||||
|
||||
#define I2C1 (0x40005400)
|
||||
#define APB1_SPEED_IN_MHZ (42)
|
||||
#define I2C1_CR1 (*(volatile uint32_t *)(I2C1))
|
||||
#define I2C1_CR2 (*(volatile uint32_t *)(I2C1 + 0x04))
|
||||
#define I2C1_OAR1 (*(volatile uint32_t *)(I2C1 + 0x08))
|
||||
#define I2C1_OAR2 (*(volatile uint32_t *)(I2C1 + 0x0c))
|
||||
#define I2C1_DR (*(volatile uint32_t *)(I2C1 + 0x10))
|
||||
#define I2C1_SR1 (*(volatile uint32_t *)(I2C1 + 0x14))
|
||||
#define I2C1_SR2 (*(volatile uint32_t *)(I2C1 + 0x18))
|
||||
#define I2C1_CCR (*(volatile uint32_t *)(I2C1 + 0x1c))
|
||||
#define I2C1_TRISE (*(volatile uint32_t *)(I2C1 + 0x20))
|
||||
|
||||
#define I2C_CR1_ENABLE (1 << 0)
|
||||
#define I2C_CR1_START (1 << 8)
|
||||
#define I2C_CR1_STOP (1 << 9)
|
||||
#define I2C_CR1_ACK (1 << 10)
|
||||
#define I2C_CR2_FREQ_MASK (0x3ff)
|
||||
#define I2C_CCR_MASK (0xfff)
|
||||
#define I2C_TRISE_MASK (0x3f)
|
||||
|
||||
|
||||
#define I2C_SR1_START (1 << 0)
|
||||
#define I2C_SR1_TX_BTF (1 << 2)
|
||||
#define I2C_SR1_ADDR_SENT (1 << 1)
|
||||
#define I2C_SR1_RX_NOTEMPTY (1 << 6)
|
||||
#define I2C_SR1_TX_EMPTY (1 << 7)
|
||||
|
||||
|
||||
#define I2C_SR2_MASTER (1 << 0)
|
||||
#define I2C_SR2_BUSY (1 << 1)
|
||||
#define I2C_SR2_XMIT (1 << 2)
|
||||
|
||||
#define APB1_CLOCK_ER (*(volatile uint32_t *)(0x40023840))
|
||||
#define APB1_CLOCK_RST (*(volatile uint32_t *)(0x40023820))
|
||||
#define I2C1_APB1_CLOCK_ER_VAL (1 << 21)
|
||||
|
||||
|
||||
static void i2c1_pins_setup(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
AHB1_CLOCK_ER |= GPIOB_AHB1_CLOCK_ER;
|
||||
/* Set mode = AF */
|
||||
reg = GPIOB_MODE & ~ (0x03 << (I2C1_SCL * 2));
|
||||
GPIOB_MODE = reg | (2 << (I2C1_SCL * 2));
|
||||
reg = GPIOB_MODE & ~ (0x03 << (I2C1_SDA * 2));
|
||||
GPIOB_MODE = reg | (2 << (I2C1_SDA * 2));
|
||||
|
||||
/* Alternate function: */
|
||||
reg = GPIOB_AFL & ~(0xf << ((I2C1_SCL) * 4));
|
||||
GPIOB_AFL = reg | (I2C1_PIN_AF << ((I2C1_SCL) * 4));
|
||||
reg = GPIOB_AFL & ~(0xf << ((I2C1_SDA) * 4));
|
||||
GPIOB_AFL = reg | (I2C1_PIN_AF << ((I2C1_SDA) * 4));
|
||||
}
|
||||
|
||||
static void i2c1_reset(void)
|
||||
{
|
||||
APB1_CLOCK_RST |= I2C1_APB1_CLOCK_ER_VAL;
|
||||
APB1_CLOCK_RST &= ~I2C1_APB1_CLOCK_ER_VAL;
|
||||
}
|
||||
|
||||
static void i2c1_send_start(void)
|
||||
{
|
||||
volatile uint32_t sr1;
|
||||
I2C1_CR1 |= I2C_CR1_START;
|
||||
do {
|
||||
sr1 = I2C1_SR1;
|
||||
} while ((sr1 & I2C_SR1_START) == 0);;
|
||||
}
|
||||
|
||||
static void i2c1_send_stop(void)
|
||||
{
|
||||
I2C1_CR1 |= I2C_CR1_STOP;
|
||||
}
|
||||
|
||||
void display_send_data(void *priv, const uint8_t *buf, int len)
|
||||
{
|
||||
volatile uint32_t sr1, sr2;
|
||||
int i;
|
||||
volatile uint8_t drval;
|
||||
uint32_t start_data = 0x00000040;
|
||||
uint8_t address = DISPLAY_I2C_ADDR;
|
||||
I2C1_CR1 &= ~I2C_CR1_ENABLE;
|
||||
I2C1_CR1 &= ~I2C_CR1_STOP;
|
||||
I2C1_CR1 &= ~I2C_CR1_ACK;
|
||||
I2C1_CR1 |= I2C_CR1_ENABLE;
|
||||
|
||||
/* Wait if the bus is busy */
|
||||
do {
|
||||
sr2 = I2C1_SR2;
|
||||
} while ((sr2 & I2C_SR2_BUSY) != 0);;
|
||||
|
||||
|
||||
/* Send a start condition */
|
||||
i2c1_send_start();
|
||||
|
||||
/* Send address + R/W = 0 */
|
||||
I2C1_DR = (address << 1);
|
||||
|
||||
do {
|
||||
sr1 = I2C1_SR1;
|
||||
} while ((sr1 & I2C_SR1_ADDR_SENT) != I2C_SR1_ADDR_SENT);
|
||||
|
||||
do {
|
||||
sr2 = I2C1_SR2;
|
||||
} while ((sr2 & (I2C_SR2_BUSY | I2C_SR2_MASTER)) != (I2C_SR2_BUSY | I2C_SR2_MASTER));;
|
||||
|
||||
I2C1_DR = start_data;
|
||||
do {
|
||||
sr1 = I2C1_SR1;
|
||||
} while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
I2C1_DR = buf[i];
|
||||
do {
|
||||
sr1 = I2C1_SR1;
|
||||
if ((sr1 & I2C_SR1_RX_NOTEMPTY) == I2C_SR1_RX_NOTEMPTY) {
|
||||
drval = I2C1_DR;
|
||||
}
|
||||
} while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0);
|
||||
}
|
||||
while ((sr1 & (I2C_SR1_TX_BTF)) == 0) {
|
||||
sr1 = I2C1_SR1;
|
||||
}
|
||||
i2c1_send_stop();
|
||||
}
|
||||
|
||||
|
||||
int i2c1_send(uint8_t address, const uint8_t *buf, int len)
|
||||
{
|
||||
volatile uint32_t sr1, sr2;
|
||||
int i;
|
||||
volatile uint8_t drval;
|
||||
I2C1_CR1 &= ~I2C_CR1_ENABLE;
|
||||
I2C1_CR1 &= ~I2C_CR1_STOP;
|
||||
I2C1_CR1 &= ~I2C_CR1_ACK;
|
||||
I2C1_CR1 |= I2C_CR1_ENABLE;
|
||||
|
||||
/* Wait if the bus is busy */
|
||||
do {
|
||||
sr2 = I2C1_SR2;
|
||||
} while ((sr2 & I2C_SR2_BUSY) != 0);;
|
||||
|
||||
|
||||
/* Send a start condition */
|
||||
i2c1_send_start();
|
||||
|
||||
/* Send address + R/W = 0 */
|
||||
I2C1_DR = (address << 1);
|
||||
|
||||
do {
|
||||
sr1 = I2C1_SR1;
|
||||
} while ((sr1 & I2C_SR1_ADDR_SENT) != I2C_SR1_ADDR_SENT);
|
||||
|
||||
do {
|
||||
sr2 = I2C1_SR2;
|
||||
} while ((sr2 & (I2C_SR2_BUSY | I2C_SR2_MASTER)) != (I2C_SR2_BUSY | I2C_SR2_MASTER));;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
I2C1_DR = buf[i];
|
||||
do {
|
||||
sr1 = I2C1_SR1;
|
||||
if ((sr1 & I2C_SR1_RX_NOTEMPTY) == I2C_SR1_RX_NOTEMPTY) {
|
||||
drval = I2C1_DR;
|
||||
}
|
||||
} while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0);
|
||||
}
|
||||
while ((sr1 & (I2C_SR1_TX_BTF)) == 0) {
|
||||
sr1 = I2C1_SR1;
|
||||
}
|
||||
i2c1_send_stop();
|
||||
return i;
|
||||
}
|
||||
|
||||
void i2c1_setup(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
i2c1_pins_setup();
|
||||
APB1_CLOCK_ER |= I2C1_APB1_CLOCK_ER_VAL;
|
||||
I2C1_CR1 &= ~I2C_CR1_ENABLE;
|
||||
i2c1_reset();
|
||||
|
||||
reg = I2C1_CR2 & ~(I2C_CR2_FREQ_MASK);
|
||||
I2C1_CR2 = reg | APB1_SPEED_IN_MHZ;
|
||||
|
||||
reg = I2C1_CCR & ~(I2C_CCR_MASK);
|
||||
// I2C1_CCR = reg | (APB1_SPEED_IN_MHZ * 5);
|
||||
I2C1_CCR = reg | 35;
|
||||
|
||||
reg = I2C1_TRISE & ~(I2C_TRISE_MASK);
|
||||
I2C1_TRISE = reg | (APB1_SPEED_IN_MHZ + 1);
|
||||
|
||||
I2C1_CR1 |= I2C_CR1_ENABLE;
|
||||
}
|
||||
|
||||
void i2c_display_init(void)
|
||||
{
|
||||
i2c1_setup();
|
||||
display_init(NULL);
|
||||
}
|
||||
|
||||
void display_send_cmd(void *priv, uint8_t cmd)
|
||||
{
|
||||
uint8_t buf[2] = {0x00, cmd};
|
||||
volatile int j;
|
||||
i2c1_send(DISPLAY_I2C_ADDR, buf, 2);
|
||||
}
|
||||
|
||||
void display_send_cmd1(void *priv, uint8_t cmd, uint8_t arg1)
|
||||
{
|
||||
uint8_t buf[3] = {0x00, cmd, arg1};
|
||||
volatile int j;
|
||||
i2c1_send(DISPLAY_I2C_ADDR, buf, 3);
|
||||
}
|
||||
|
||||
void display_send_cmd2(void *priv, uint8_t cmd, uint8_t arg1, uint8_t arg2)
|
||||
{
|
||||
uint8_t buf[4] = {0x00, cmd, arg1, arg2};
|
||||
volatile int j;
|
||||
i2c1_send(DISPLAY_I2C_ADDR, buf, 3);
|
||||
}
|
||||
|
12
i2c.h
Normal file
12
i2c.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef I2C_H_INCLUDED
|
||||
#define I2C_H_INCLUDED
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
void i2c1_setup(void);
|
||||
void i2c1_write(uint8_t addr, const char byte);
|
||||
uint8_t i2c1_read(uint8_t addr);
|
||||
int i2c1_send(uint8_t address, const uint8_t *buf, int len);
|
||||
int i2c1_send_data(uint8_t address, const uint8_t *buf, int len);
|
||||
|
||||
#endif
|
58
led.c
Normal file
58
led.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "system.h"
|
||||
#include "led.h"
|
||||
|
||||
void led_setup(uint32_t led)
|
||||
{
|
||||
uint32_t reg;
|
||||
if (led == BLUE_LED) {
|
||||
AHB1_CLOCK_ER |= GPIOB_AHB1_CLOCK_ER;
|
||||
reg = GPIOB_MODE & ~ (0x03 << (led * 2));
|
||||
GPIOB_MODE = reg | (1 << (led * 2));
|
||||
reg = GPIOB_PUPD & (0x03 << (led * 2));
|
||||
GPIOB_PUPD = reg | (0x02 << (led * 2));
|
||||
} else {
|
||||
AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER;
|
||||
reg = GPIOA_MODE & ~ (0x03 << (led * 2));
|
||||
GPIOA_MODE = reg | (1 << (led * 2));
|
||||
reg = GPIOA_PUPD & (0x03 << (led * 2));
|
||||
GPIOA_PUPD = reg | (0x02 << (led * 2));
|
||||
}
|
||||
led_off(led);
|
||||
}
|
||||
|
||||
void pio_on(uint32_t pio)
|
||||
{
|
||||
if (pio == BLUE_LED)
|
||||
GPIOB_BSRR |= (1 << pio);
|
||||
else
|
||||
GPIOA_BSRR |= (1 << pio);
|
||||
}
|
||||
|
||||
void pio_off(uint32_t pio)
|
||||
{
|
||||
if (pio == BLUE_LED)
|
||||
GPIOB_BSRR |= (1 << (pio + 16));
|
||||
else
|
||||
GPIOA_BSRR |= (1 << (pio + 16));
|
||||
}
|
||||
|
||||
void pio_toggle(uint32_t pio)
|
||||
{
|
||||
uint32_t reg;
|
||||
if (pio == BLUE_LED)
|
||||
reg = GPIOB_ODR;
|
||||
else
|
||||
reg = GPIOA_ODR;
|
||||
if ((reg & (1 << pio)) == (1 << pio))
|
||||
pio_off(pio);
|
||||
else
|
||||
pio_on(pio);
|
||||
}
|
||||
|
15
led.h
Normal file
15
led.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef LED_H
|
||||
#define LED_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "system.h"
|
||||
|
||||
void led_setup(uint32_t led);
|
||||
void pio_on(uint32_t pio);
|
||||
void pio_off(uint32_t pio);
|
||||
void pio_toggle(uint32_t pio);
|
||||
|
||||
#define led_on pio_on
|
||||
#define led_off pio_off
|
||||
#define led_toggle pio_toggle
|
||||
#endif
|
1
lib/unicore-mx
Submodule
1
lib/unicore-mx
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 3ddec02525f0b507c8a54f5dbad0df9340772a36
|
140
main.c
Normal file
140
main.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "system.h"
|
||||
#include "usecfs.h"
|
||||
#include "led.h"
|
||||
#include "display.h"
|
||||
#include <wolfssl/wolfcrypt/random.h>
|
||||
#include "spi_flash.h"
|
||||
#include "uart.h"
|
||||
#include "systick.h"
|
||||
#include "ui.h"
|
||||
#include "sdcard.h"
|
||||
#include "button.h"
|
||||
extern uint32_t cpu_freq;
|
||||
|
||||
#define BLINK_INTERVAL 500
|
||||
|
||||
static int sdcard_detected = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
static void bootlevel_0(void)
|
||||
{
|
||||
WC_RNG hwrng;
|
||||
clock_pll_on(0);
|
||||
uart2_setup(115200, 8, 0, 1);
|
||||
printf("Console on USART2 Enabled.\r\n");
|
||||
printf("\r\n=====================\r\n");
|
||||
printf("Entering bootlevel 0.\r\n");
|
||||
// led_setup(RED_LED);
|
||||
// led_setup(GREEN_LED);
|
||||
led_setup(YELLOW_LED);
|
||||
led_setup(BLUE_LED);
|
||||
wc_InitRng(&hwrng);
|
||||
printf("RNG enabled");
|
||||
systick_enable();
|
||||
printf("System clock started.\r\n");
|
||||
button_init();
|
||||
printf("Buttons initialized.\r\n");
|
||||
}
|
||||
|
||||
static void bootlevel_1(void)
|
||||
{
|
||||
uint16_t spiflash_vendor;
|
||||
int sdcard_present;
|
||||
printf("=====================\r\n");
|
||||
printf("Entering bootlevel 1.\r\n");
|
||||
|
||||
printf("Probing SPI flash...\r\n");
|
||||
spi_init(0,0);
|
||||
spiflash_vendor = spi_flash_probe();
|
||||
if ((spiflash_vendor & 0xFF00) >> 8 != 0xBF) {
|
||||
printf("FATAL: Unexpected SPI flash detected.\r\n");
|
||||
panic();
|
||||
} else {
|
||||
printf("SPI flash detected (Vendor: %02X Model: %02X)\r\n", (spiflash_vendor & 0xFF00) >> 8, (spiflash_vendor & 0xFF));
|
||||
}
|
||||
|
||||
printf("Initializing SDIO module\r\n");
|
||||
sdcard_hw_init();
|
||||
|
||||
printf("Probing SD card slot...\r\n");
|
||||
if (sdcard_detect() != 0) {
|
||||
printf("SD Card not found.\r\n");
|
||||
} else {
|
||||
printf("SD Card detected.\r\n");
|
||||
led_on(YELLOW_LED);
|
||||
sdcard_detected = 1;
|
||||
}
|
||||
|
||||
i2c_display_init();
|
||||
printf("Display initialized.\r\n");
|
||||
|
||||
printf("Displaying splash screen...\r\n");
|
||||
|
||||
ui_init();
|
||||
printf("UI initialized.\r\n");
|
||||
printf("System up and running.\r\n\n\n");
|
||||
}
|
||||
|
||||
|
||||
void process_button(uint16_t press, int hold)
|
||||
{
|
||||
char c = bu2c(press);
|
||||
if (!hold)
|
||||
printf("Pressed '%c'.\r\n", c);
|
||||
else
|
||||
printf("Held '%c'.\r\n", c);
|
||||
ui_button_press(press);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int hb = 1;
|
||||
int fs_on = 0;
|
||||
int ret;
|
||||
volatile uint32_t poll_time = 0;
|
||||
uint32_t bstatus = 0;
|
||||
|
||||
const uint32_t hb_len = 5000;
|
||||
const uint32_t hb_pulse = 5;
|
||||
|
||||
bootlevel_0();
|
||||
bootlevel_1();
|
||||
|
||||
while(1) {
|
||||
hb = 1;
|
||||
led_on(BLUE_LED);
|
||||
poll_time = jiffies;
|
||||
|
||||
/* SD Card detection */
|
||||
if (!sdcard_detected) {
|
||||
sdcard_detected = !!(0 == sdcard_detect());
|
||||
if (sdcard_detected) {
|
||||
printf("Inserted SD Card");
|
||||
ui_sdcard_insert();
|
||||
led_on(YELLOW_LED);
|
||||
}
|
||||
}
|
||||
ui_keepalive(hb_len);
|
||||
|
||||
do {
|
||||
WFI();
|
||||
ret = button_poll(process_button);
|
||||
if (jiffies - poll_time > hb_pulse) {
|
||||
if (hb) {
|
||||
hb = 0;
|
||||
led_off(BLUE_LED);
|
||||
}
|
||||
}
|
||||
} while ((jiffies - poll_time) < hb_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
37
mem.c
Normal file
37
mem.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
extern unsigned int _start_heap;
|
||||
#define NULL (((void *)0))
|
||||
|
||||
|
||||
void * _sbrk(unsigned int incr)
|
||||
{
|
||||
static unsigned char *heap = (unsigned char *)&_start_heap;
|
||||
void *old_heap = heap;
|
||||
if (((incr >> 2) << 2) != incr)
|
||||
incr = ((incr >> 2) + 1) << 2;
|
||||
|
||||
if (heap == NULL)
|
||||
heap = (unsigned char *)&_start_heap;
|
||||
else
|
||||
heap += incr;
|
||||
return old_heap;
|
||||
}
|
||||
|
||||
void * _sbrk_r(unsigned int incr)
|
||||
{
|
||||
static unsigned char *heap = NULL;
|
||||
void *old_heap = heap;
|
||||
if (((incr >> 2) << 2) != incr)
|
||||
incr = ((incr >> 2) + 1) << 2;
|
||||
|
||||
if (old_heap == NULL)
|
||||
old_heap = heap = (unsigned char *)&_start_heap;
|
||||
heap += incr;
|
||||
return old_heap;
|
||||
}
|
||||
|
35
newlib.c
Normal file
35
newlib.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int _close(int fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _fstat(int fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _lseek(int fd, int whence, int off)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _read(uint8_t *buf, int len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _isatty(int fd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
34
random.c
Normal file
34
random.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include "system.h"
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t random_uint32(void)
|
||||
{
|
||||
int i;
|
||||
uint32_t rand;
|
||||
/* enable RNG peripheral clock */
|
||||
AHB2_CLOCK_ER |= RNG_AHB2_CLOCK_ER;
|
||||
/* enable RNG interrupt, set IE bit in RNG->CR register */
|
||||
RNG_CR |= RNG_CR_IE;
|
||||
|
||||
/* enable RNG, set RNGEN bit in RNG->CR. Activates RNG,
|
||||
* RNG_LFSR, and error detector */
|
||||
RNG_CR |= RNG_CR_RNGEN;
|
||||
|
||||
/* verify no errors, make sure SEIS and CEIS bits are 0
|
||||
* in RNG->SR register */
|
||||
if (RNG_SR & (RNG_SR_SECS | RNG_SR_CECS))
|
||||
return 0;
|
||||
|
||||
/* wait until RNG number is ready */
|
||||
while ((RNG_SR & RNG_SR_DRDY) == 0)
|
||||
;
|
||||
/* get value */
|
||||
rand = RNG_DR;
|
||||
return rand;
|
||||
}
|
790
sdcard.c
Normal file
790
sdcard.c
Normal file
|
@ -0,0 +1,790 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
* Based on work by Chuck M. (see https://github.com/ChuckM/stm32f4-sdio-driver/)
|
||||
*
|
||||
* Permission to release under the terms of GPLv2 are granted by the
|
||||
* copyright holders.
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
|
||||
/*
|
||||
* SDIO Bus Driver layer. This code sends commands and drives
|
||||
* the SDIO peripheral on the STM32F4xx, there is a layer above
|
||||
* this, the SD Card driver, which uses this driver to talk to
|
||||
* SD Cards. The SPI driver can also talk to SD Cards, hence the
|
||||
* split at this layer.
|
||||
*
|
||||
* Note that the simple implementation for the SDIO driver runs
|
||||
* in a 'polled' mode. This is easier to explain and debug and
|
||||
* sufficient for the first few projects. A more sophisticated
|
||||
* version with DMA and interrupts will follow.
|
||||
*
|
||||
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "system.h"
|
||||
#include "sdcard.h"
|
||||
|
||||
#if (!defined(BLOCK_SIZE)) || (BLOCK_SIZE != 512)
|
||||
# error BLOCK_SIZE undefined or invalid
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (void *)(0x00000000)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper defines to pull out various bit fields of the CSD for
|
||||
* the size calculation.
|
||||
*/
|
||||
#define SDIO_CSD_VERSION(x) stm32_sdio_bit_slice(x->csd, 128, 127, 126)
|
||||
#define SDIO_CSD1_CSIZE_MULT(x) stm32_sdio_bit_slice(x->csd, 128, 49, 47)
|
||||
#define SDIO_CSD1_RBLKLEN(x) stm32_sdio_bit_slice(x->csd, 128, 83, 80)
|
||||
#define SDIO_CSD1_CSIZE(x) stm32_sdio_bit_slice(x->csd, 128, 73, 62)
|
||||
#define SDIO_CSD2_CSIZE(x) stm32_sdio_bit_slice(x->csd, 128, 69, 48)
|
||||
|
||||
/*
|
||||
* Conveniently swaps the bytes in a long around
|
||||
* used by the SCR code.
|
||||
*/
|
||||
#define byte_swap(val) \
|
||||
asm("rev %[swap], %[swap]" : [swap] "=r" (val) : "0" (val));
|
||||
|
||||
static const uint32_t sdio_pins[5] = { 8, 9, 10, 11, 12}; /* GPIOC */
|
||||
static const uint32_t sdio_cmd_pin = 2; /* GPIOD2 */
|
||||
static const uint32_t sdio_detect_pin = 8; /* GPIOA8 */
|
||||
static const uint32_t sdio_af = 12;
|
||||
static struct dev_sd SD;
|
||||
|
||||
/*
|
||||
* sdio_bus
|
||||
*
|
||||
* Set the bus width and the clock speed for the
|
||||
* SDIO bus.
|
||||
*
|
||||
* Returns 0 on success
|
||||
* -1 illegal bit specification
|
||||
* -2 illegal clock specification
|
||||
*/
|
||||
static int
|
||||
stm32_sdio_bus(struct dev_sd *sd, int bits, enum SDIO_CLOCK_DIV freq) {
|
||||
int clkreg = 0;
|
||||
|
||||
switch (bits) {
|
||||
case 1:
|
||||
clkreg |= SDIO_CLKCR_WIDBUS_1;
|
||||
break;
|
||||
case 4:
|
||||
clkreg |= SDIO_CLKCR_WIDBUS_4;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
switch (freq) {
|
||||
case SDIO_24MHZ:
|
||||
break;
|
||||
case SDIO_16MHZ:
|
||||
clkreg |= 1;
|
||||
break;
|
||||
case SDIO_12MHZ:
|
||||
clkreg |= 2;
|
||||
break;
|
||||
case SDIO_8MHZ:
|
||||
clkreg |= 8;
|
||||
break;
|
||||
case SDIO_4MHZ:
|
||||
clkreg |= 10;
|
||||
break;
|
||||
case SDIO_1MHZ:
|
||||
clkreg |= 46;
|
||||
break;
|
||||
case SDIO_400KHZ:
|
||||
clkreg |= 118;
|
||||
break;
|
||||
default:
|
||||
return -2;
|
||||
}
|
||||
clkreg |= SDIO_CLKCR_CLKEN;
|
||||
SDIO_CLKCR = clkreg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the state of the SDIO bus and peripheral. This code tries
|
||||
* to reset the bus *AND* the card if one is plugged in. The bus
|
||||
* can be reset by software but the card is reset by powering it down.
|
||||
*
|
||||
* The SDIO_POWER_STATE tells the code which state to leave the bus in,
|
||||
* powered up or powered down.
|
||||
*
|
||||
* If the state is POWER_ON, then the bus is reset to 400Khz, 1 bit wide
|
||||
* which is what he spec requires. Once the type and capabilities of the
|
||||
* card have been determined, it can be upgraded.
|
||||
*/
|
||||
void
|
||||
stm32_sdio_reset(struct dev_sd *sd, enum SDIO_POWER_STATE state) {
|
||||
|
||||
/* Step 1 power off the interface */
|
||||
SDIO_POWER = SDIO_POWER_PWRCTRL_PWROFF;
|
||||
|
||||
/* reset the SDIO peripheral interface */
|
||||
APB2_CLOCK_RST |= SDIO_APB2_CLOCK_ER_VAL;
|
||||
APB2_CLOCK_RST &= ~SDIO_APB2_CLOCK_ER_VAL;
|
||||
|
||||
if (state == SDIO_POWER_ON) {
|
||||
SDIO_POWER = SDIO_POWER_PWRCTRL_PWRON;
|
||||
stm32_sdio_bus(sd, 1, SDIO_400KHZ); // required by the spec
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The error message catalog.
|
||||
*/
|
||||
static const char *__sdio_error_msgs[] = {
|
||||
"Success",
|
||||
"Command Timeout", // -1
|
||||
"Command CRC Failure", // -2
|
||||
"Soft Timeout (No Response)", // -3
|
||||
"Data CRC Failure", // -4
|
||||
"RX FIFO Overrun", // -5
|
||||
"TX FIFO Underrun", // -6
|
||||
"Unsupported Card" // -7
|
||||
};
|
||||
|
||||
#define SDIO_ESUCCESS 0
|
||||
#define SDIO_ECTIMEOUT -1
|
||||
#define SDIO_ECCRCFAIL -2
|
||||
#define SDIO_ENORESP -3
|
||||
#define SDIO_EDCRCFAIL -4
|
||||
#define SDIO_ERXOVERR -5
|
||||
#define SDIO_ETXUNDER -6
|
||||
#define SDIO_EBADCARD -7
|
||||
#define SDIO_EUNKNOWN -8
|
||||
|
||||
/*
|
||||
* Return a text string description of the error code.
|
||||
*/
|
||||
const char *
|
||||
stm32_sdio_errmsg(int err) {
|
||||
return (err <= SDIO_EUNKNOWN) ? (const char *) "Unknown Error" :
|
||||
__sdio_error_msgs[0-err];
|
||||
}
|
||||
|
||||
/*
|
||||
* stm32_sdio_bit_slice - helper function
|
||||
*
|
||||
* A number of the things the SDIO returns are in bit
|
||||
* fields. This code is designed to slice out a range
|
||||
* of bits and return them as a value (up to 32 bits
|
||||
* worth).
|
||||
*/
|
||||
uint32_t
|
||||
stm32_sdio_bit_slice(uint32_t a[], int bits, int msb, int lsb) {
|
||||
uint32_t t;
|
||||
int i;
|
||||
|
||||
if (((msb >= bits) || (msb < 0)) ||
|
||||
(lsb > msb) ||
|
||||
((lsb < 0) || (lsb >= bits))) {
|
||||
return 0;
|
||||
}
|
||||
t = 0;
|
||||
for (i = msb; i > lsb; i--) {
|
||||
t |= (a[((bits-1) - i)/32] >> (i % 32)) & 0x1;
|
||||
t <<= 1;
|
||||
}
|
||||
t |= (a[((bits-1) - lsb)/32] >> (lsb % 32)) & 0x1;
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* A convienence define. These are the flags we care about when
|
||||
* sending a command. During command processing SDIO_STA_CMDACT
|
||||
* will be set.
|
||||
*/
|
||||
#define COMMAND_FLAGS (SDIO_STA_CMDSENT |\
|
||||
SDIO_STA_CCRCFAIL |\
|
||||
SDIO_STA_CMDREND |\
|
||||
SDIO_STA_CTIMEOUT)
|
||||
|
||||
/*
|
||||
* Send a command over the SDIO bus.
|
||||
* Passed a command (8 bit value) and an argument (32 bit value)
|
||||
* This command figures out if the command will return a short (32 bit)
|
||||
* or long (64 bit) response. It is up to the calling program to pull
|
||||
* data from the long response commands.
|
||||
* Passed:
|
||||
* cmd - Command to execute
|
||||
* int sdcard_sense(void *dev);
|
||||
*
|
||||
* arg - Argument to pass to the command
|
||||
* buf - pointer to a long aligned buffer if data
|
||||
* len - expected length of buffer (in bytes)
|
||||
*/
|
||||
int
|
||||
stm32_sdio_command(struct dev_sd *sd, uint32_t cmd, uint32_t arg)
|
||||
{
|
||||
uint32_t tmp_val;
|
||||
int error = 0;
|
||||
|
||||
tmp_val = SDIO_CMD & ~0x7ff; // Read pre-existing state
|
||||
tmp_val |= (cmd & SDIO_CMD_CMDINDEX_MSK); // Put the Command in
|
||||
tmp_val |= SDIO_CMD_CPSMEN; // We'll be running CPSM
|
||||
|
||||
switch(cmd) {
|
||||
case 0:
|
||||
tmp_val |= SDIO_CMD_WAITRESP_NO_0;
|
||||
break;
|
||||
case 2:
|
||||
case 9:
|
||||
tmp_val |= SDIO_CMD_WAITRESP_LONG;
|
||||
break;
|
||||
default:
|
||||
tmp_val |= SDIO_CMD_WAITRESP_SHORT; // the common case
|
||||
break;
|
||||
}
|
||||
/* If a data transaction is in progress, wait for it to finish */
|
||||
|
||||
while ((cmd != 12) & (SDIO_STA & (SDIO_STA_RXACT | SDIO_STA_TXACT)));;
|
||||
|
||||
|
||||
/*
|
||||
* EXECUTE:
|
||||
* o Reset all status bits
|
||||
* o Put ARG into SDIO ARG
|
||||
* o reset the error indicator
|
||||
* o Enable all interrupts.
|
||||
* o Do the command
|
||||
*/
|
||||
SDIO_ICR = 0x7ff; // Reset everything that isn't bolted down.
|
||||
SDIO_ARG = arg;
|
||||
SDIO_CMD = tmp_val;
|
||||
/*
|
||||
* In a polled mode we should be able to just read the status bits
|
||||
* directly.
|
||||
*/
|
||||
tmp_val = 0;
|
||||
do {
|
||||
tmp_val |= (SDIO_STA & 0x7ff);
|
||||
} while ((SDIO_STA & SDIO_STA_CMDACT) || (! tmp_val));;
|
||||
SDIO_ICR = tmp_val;
|
||||
|
||||
/*
|
||||
* Compute the error here. Which can be one of
|
||||
* -- Success (either CMDSENT or CMDREND depending on response)
|
||||
* -- Timeout (based on CTIMEOUT)
|
||||
* -- No Response (based on no response in the time alloted)
|
||||
* -- CRC Error (based on CCRCFAIL)
|
||||
*/
|
||||
if (! tmp_val) {
|
||||
error = SDIO_ENORESP;
|
||||
} else if (tmp_val & SDIO_STA_CCRCFAIL) {
|
||||
error = SDIO_ECCRCFAIL;
|
||||
} else if (tmp_val & (SDIO_STA_CMDREND | SDIO_STA_CMDSENT)) {
|
||||
error = SDIO_ESUCCESS;
|
||||
} else if (tmp_val & SDIO_STA_CTIMEOUT) {
|
||||
error = SDIO_ECTIMEOUT;
|
||||
} else {
|
||||
error = SDIO_EUNKNOWN;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* our static data buffer we use for data movement commands */
|
||||
|
||||
/*
|
||||
* Helper function - sdio_select
|
||||
*
|
||||
* This function "selects" a card using CMD7, note that if
|
||||
* you select card 0 that deselects the card (RCA is not allowed
|
||||
* to be 0)
|
||||
*/
|
||||
static int
|
||||
sdio_select(struct dev_sd *sd, int rca) {
|
||||
int err;
|
||||
|
||||
err = stm32_sdio_command(sd, 7, rca << 16);
|
||||
if ((rca == 0) && (err == SDIO_ECTIMEOUT)) {
|
||||
return 0; // "cheat" a timeout selecting 0 is a successful deselect
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function - sdio_scr
|
||||
*
|
||||
* Unlike the CID and CSD functions this function transfers data
|
||||
* so it needs to use the DPSM.
|
||||
*
|
||||
* Note that data over the wire is byte swapped so we swap it back
|
||||
* to "fix" it.
|
||||
*
|
||||
* Note when this return 0 the first two longs in the data_buf are
|
||||
* the SCR register.
|
||||
*/
|
||||
|
||||
static uint32_t data_buf[129];
|
||||
static int
|
||||
sdio_scr(struct dev_sd *sd, SDIO_CARD c) {
|
||||
int err;
|
||||
uint32_t tmp_reg;
|
||||
int ndx;
|
||||
int data_len;
|
||||
|
||||
/* Select the card */
|
||||
err = sdio_select(sd, c->rca);
|
||||
if (! err) {
|
||||
/* Set the Block Size */
|
||||
err = stm32_sdio_command(sd, 16, 8);
|
||||
if (! err) {
|
||||
/* APPCMD (our RCA) */
|
||||
err = stm32_sdio_command(sd, 55, c->rca << 16);
|
||||
if (! err) {
|
||||
SDIO_ICR = 0xFFFFFFFF; /* Clear all status flags */
|
||||
SDIO_DTIMER = 0xffffffff;
|
||||
SDIO_DLEN = 8;
|
||||
SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 |
|
||||
SDIO_DCTRL_DTDIR |
|
||||
SDIO_DCTRL_DTEN;
|
||||
/* ACMD51 - Send SCR */
|
||||
err = stm32_sdio_command(sd, 51, 0);
|
||||
if (! err) {
|
||||
data_len = 0;
|
||||
do {
|
||||
tmp_reg = SDIO_STA;
|
||||
if (tmp_reg & SDIO_STA_RXDAVL) {
|
||||
data_buf[data_len++] = SDIO_FIFO;
|
||||
}
|
||||
} while (tmp_reg & SDIO_STA_RXACT);
|
||||
if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
|
||||
if (tmp_reg & SDIO_STA_DCRCFAIL) {
|
||||
err = SDIO_EDCRCFAIL;
|
||||
} else if (tmp_reg & SDIO_STA_RXOVERR) {
|
||||
err = SDIO_ERXOVERR;
|
||||
} else {
|
||||
err = SDIO_EUNKNOWN; // unknown error
|
||||
}
|
||||
}
|
||||
if (! err) {
|
||||
for (ndx = 0; ndx < 2; ndx++) {
|
||||
byte_swap(data_buf[ndx]);
|
||||
c->scr[ndx] = data_buf[ndx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(void) sdio_select(sd, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a Block from our Card
|
||||
*
|
||||
* NB: There is a possibly useless test in this code, during the read
|
||||
* phase it allows that the SDIO card might try to send more than BLOCK_SIZE
|
||||
* bytes (128 32 bit longs) and allows it to do so, constantly over
|
||||
* writing the last long in the just-in-case-over-long-by-1 data buffer.
|
||||
* To compromise the system you would need a borked or custom crafted
|
||||
* sdio card which did that.
|
||||
*/
|
||||
|
||||
int sdcard_read(void *dev, void *_buf, uint32_t lba)
|
||||
{
|
||||
int err;
|
||||
uint32_t tmp_reg;
|
||||
uint32_t addr = lba;
|
||||
uint8_t *t;
|
||||
int ndx, bdx = 0;
|
||||
struct dev_sd *sd = &SD;
|
||||
uint32_t *buf = _buf;
|
||||
uint32_t buf_len = 0;
|
||||
|
||||
if (! SDIO_CARD_CCS(sd->card)) {
|
||||
addr = lba * BLOCK_SIZE; // non HC cards use byte address
|
||||
}
|
||||
err = sdio_select(sd, sd->card->rca);
|
||||
if (! err) {
|
||||
err = stm32_sdio_command(sd, 16, BLOCK_SIZE);
|
||||
if (!err) {
|
||||
SDIO_DTIMER = 0xffffffff;
|
||||
SDIO_DLEN = BLOCK_SIZE;
|
||||
SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_9 |
|
||||
SDIO_DCTRL_DTDIR |
|
||||
SDIO_DCTRL_DTEN;
|
||||
err = stm32_sdio_command(sd, 17, addr);
|
||||
if (! err) {
|
||||
buf_len = 0;
|
||||
do {
|
||||
tmp_reg = SDIO_STA;
|
||||
if (tmp_reg & SDIO_STA_RXDAVL) {
|
||||
buf[buf_len] = SDIO_FIFO;
|
||||
if (buf_len < 128) {
|
||||
++buf_len;
|
||||
}
|
||||
}
|
||||
} while (tmp_reg & SDIO_STA_RXACT);
|
||||
if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
|
||||
if (tmp_reg & SDIO_STA_DCRCFAIL) {
|
||||
err = SDIO_EDCRCFAIL;
|
||||
} else if (tmp_reg & SDIO_STA_RXOVERR) {
|
||||
err = SDIO_ERXOVERR;
|
||||
} else {
|
||||
err = SDIO_EUNKNOWN; // Unknown Error!
|
||||
}
|
||||
} else {
|
||||
err = BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// deselect the card
|
||||
(void) sdio_select(sd, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a Block from our Card
|
||||
*/
|
||||
int sdcard_write(void *dev, void *_buf, uint32_t lba)
|
||||
{
|
||||
int err;
|
||||
uint32_t tmp_reg;
|
||||
uint32_t addr = lba;
|
||||
uint8_t *t;
|
||||
int ndx;
|
||||
struct dev_sd *sd = &SD;
|
||||
SDIO_CARD c;
|
||||
uint32_t *buf = _buf;
|
||||
uint32_t buf_len = 0;
|
||||
|
||||
c = SD.card;
|
||||
|
||||
|
||||
if (! SDIO_CARD_CCS(c)) {
|
||||
addr = lba * BLOCK_SIZE; // non HC cards use byte address
|
||||
}
|
||||
|
||||
err = sdio_select(sd, c->rca);
|
||||
if (! err) {
|
||||
/* Set Block Size to BLOCK_SIZE */
|
||||
err = stm32_sdio_command(sd, 16, BLOCK_SIZE);
|
||||
if (!err) {
|
||||
SDIO_DTIMER = 0xffffffff;
|
||||
SDIO_DLEN = BLOCK_SIZE;
|
||||
SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_9 |
|
||||
SDIO_DCTRL_DTEN;
|
||||
err = stm32_sdio_command(sd, 24, addr);
|
||||
if (! err) {
|
||||
do {
|
||||
tmp_reg = SDIO_STA;
|
||||
if (tmp_reg & SDIO_STA_TXFIFOHE) {
|
||||
SDIO_FIFO = buf[buf_len];
|
||||
if (buf_len < 128) {
|
||||
++buf_len;
|
||||
}
|
||||
}
|
||||
} while (tmp_reg & SDIO_STA_TXACT);
|
||||
if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
|
||||
if (tmp_reg & SDIO_STA_DCRCFAIL) {
|
||||
err = SDIO_EDCRCFAIL;
|
||||
} else if (tmp_reg & SDIO_STA_TXUNDERR) {
|
||||
err = SDIO_ETXUNDER;
|
||||
} else {
|
||||
err = SDIO_EUNKNOWN; // Unknown Error!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// deselect the card
|
||||
(void) sdio_select(sd, 0);
|
||||
if (err == 0)
|
||||
return BLOCK_SIZE;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* sdio-status - Get Card Status page
|
||||
*
|
||||
* This function fetches the SD Card Status page and
|
||||
* copies it into the CARD structure.
|
||||
*/
|
||||
/*
|
||||
int
|
||||
sdio_status(SDIO_CARD c) {
|
||||
uint32_t tmp_reg;
|
||||
int ndx;
|
||||
int err;
|
||||
|
||||
err = sdio_select(c->rca);
|
||||
if (! err) {
|
||||
err = stm32_sdio_command(16, 64);
|
||||
if (! err) {
|
||||
err = stm32_sdio_command(55, c->rca << 16);
|
||||
if (! err) {
|
||||
SDIO_DTIMER = 0xffffffff;
|
||||
SDIO_DLEN = 64;
|
||||
SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_6 |
|
||||
SDIO_DCTRL_DTDIR |
|
||||
SDIO_DCTRL_DTEN; */
|
||||
/* ACMD13 - Send Status Reg */ /*
|
||||
err = stm32_sdio_command(13, 0);
|
||||
if (! err) {
|
||||
data_len = 0;
|
||||
do {
|
||||
tmp_reg = SDIO_STA;
|
||||
if (tmp_reg & SDIO_STA_RXDAVL) {
|
||||
data_buf[data_len] = SDIO_FIFO;
|
||||
if (data_len < 128) {
|
||||
++data_len;
|
||||
}
|
||||
}
|
||||
} while (tmp_reg & SDIO_STA_RXACT);
|
||||
if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
|
||||
if (tmp_reg & SDIO_STA_DCRCFAIL) {
|
||||
err = SDIO_EDCRCFAIL;
|
||||
} else if (tmp_reg & SDIO_STA_RXOVERR) {
|
||||
err = SDIO_ERXOVERR;
|
||||
} else {
|
||||
err = SDIO_EUNKNOWN; // Unknown Error!
|
||||
}
|
||||
} else {
|
||||
for (ndx = 0; ndx < 16; ndx++) {
|
||||
byte_swap(data_buf[ndx]);
|
||||
c->status[ndx] = data_buf[ndx];
|
||||
}
|
||||
}
|
||||
(void) sdio_select(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
*/
|
||||
|
||||
static struct SDIO_CARD_DATA sdio_card_data;
|
||||
#define MAX_RETRIES 5
|
||||
|
||||
/*
|
||||
* stm32_sdio_open - Prepare to use SDIO card
|
||||
*
|
||||
* This function resets the SDIO bus and identifies the
|
||||
* card (if any) that is plugged in. If there is no card
|
||||
* present, or an error in figuring out what the card is
|
||||
* (for example its an old MMC card) the function returns
|
||||
* NULL. If it fails and you have logging enabled you can
|
||||
* look at the last few commands sent.
|
||||
*/
|
||||
SDIO_CARD
|
||||
stm32_sdio_open(struct dev_sd *sd) {
|
||||
int err;
|
||||
int i;
|
||||
uint8_t *t;
|
||||
uint32_t tmp_reg;
|
||||
SDIO_CARD res = &sdio_card_data;
|
||||
|
||||
// basically bset(0, sdio_card_data)
|
||||
t = (uint8_t *) &sdio_card_data;
|
||||
for (i = 0; i < (int) sizeof(sdio_card_data); i++) {
|
||||
*t++ = 0;
|
||||
}
|
||||
stm32_sdio_reset(sd, SDIO_POWER_ON);
|
||||
err = stm32_sdio_command(sd, 0, 0);
|
||||
if (!err) {
|
||||
err = stm32_sdio_command(sd, 8, 0x1aa);
|
||||
if (!err) {
|
||||
// Woot! We support CMD8 so we're a v2 card at least */
|
||||
tmp_reg = SDIO_RESP1;
|
||||
sdio_card_data.props = 1;
|
||||
i = 0;
|
||||
err = stm32_sdio_command(sd, 5, 0);
|
||||
if (! err) {
|
||||
// It is an SDIO card which is unsupported!
|
||||
err = SDIO_EBADCARD;
|
||||
return NULL;
|
||||
}
|
||||
do {
|
||||
err = stm32_sdio_command(sd, 55, 0); // broadcast ACMD
|
||||
if (err) {
|
||||
break; // try again
|
||||
}
|
||||
// Testing Card Busy, Voltage match, and capacity
|
||||
err = stm32_sdio_command(sd, 41, 0xc0100000);
|
||||
if (err != -2) { // Expect CCRCFAIL here
|
||||
break; // try again
|
||||
}
|
||||
tmp_reg = SDIO_RESP1; // what did the card send?
|
||||
if ((tmp_reg & 0x80000000) == 0) {
|
||||
continue; // still powering up
|
||||
}
|
||||
res->ocr = tmp_reg; // Ok OCR is valid
|
||||
break;
|
||||
} while (++i < MAX_RETRIES);
|
||||
if (res->ocr) {
|
||||
err = stm32_sdio_command(sd, 2, 0);
|
||||
if (! err) {
|
||||
res->cid[0] = SDIO_RESP1;
|
||||
res->cid[1] = SDIO_RESP2;
|
||||
res->cid[2] = SDIO_RESP3;
|
||||
res->cid[3] = SDIO_RESP4;
|
||||
err = stm32_sdio_command(sd, 3, 0); // get the RCA
|
||||
if (! err) {
|
||||
tmp_reg = SDIO_RESP1;
|
||||
res->rca = (tmp_reg >> 16) & 0xffff;
|
||||
if (! res->rca) {
|
||||
/*
|
||||
* If the card says '0' tell it to pick
|
||||
* we assume this will work because the
|
||||
* previous send RCA worked and the card
|
||||
* should be in the ident state if it is
|
||||
* functioning correctly.
|
||||
*/
|
||||
(void) stm32_sdio_command(sd, 3, 0); // try again
|
||||
tmp_reg = SDIO_RESP1;
|
||||
res->rca = (tmp_reg >> 16) & 0xffff;
|
||||
}
|
||||
err = stm32_sdio_command(sd, 9, res->rca << 16);
|
||||
if (! err) {
|
||||
res->csd[0] = SDIO_RESP1;
|
||||
res->csd[1] = SDIO_RESP2;
|
||||
res->csd[2] = SDIO_RESP3;
|
||||
res->csd[3] = SDIO_RESP4;
|
||||
err = sdio_scr(sd, res); // Capture the SCR
|
||||
if (! err) {
|
||||
/* All SD Cards support 4 bit bus and 24Mhz */
|
||||
err = sdio_select(sd, res->rca);
|
||||
if (! err) {
|
||||
err = stm32_sdio_command(sd, 55, res->rca << 16);
|
||||
if (! err) {
|
||||
err = stm32_sdio_command(sd, 6, 2);
|
||||
if (! err) {
|
||||
//XXX stm32_sdio_bus(4, SDIO_24MHZ);
|
||||
//Seems we have speed issues for now...
|
||||
stm32_sdio_bus(sd, 4, SDIO_12MHZ);
|
||||
(void) sdio_select(sd, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Compute the size of the card based on fields in the CSD
|
||||
* block. There are two kinds, V1 or V2.
|
||||
* In the V1 Case :
|
||||
* Size = 1<<BLOCK_LEN * 1<<(MULT+2) * (C_SIZE+1) bytes.
|
||||
* In the V2 Case :
|
||||
* Size = (C_SIZE + 1) * BLOCK_SIZEK bytes.
|
||||
* But for our structure we want the size in BLOCK_SIZE byte "blocks"
|
||||
* since that is the addressing unit we're going to export so
|
||||
* we compute the size / BLOCK_SIZE as the "size" for the structure.
|
||||
*/
|
||||
|
||||
if (! err) {
|
||||
res->size = 0;
|
||||
switch (SDIO_CSD_VERSION(res)) {
|
||||
case 0:
|
||||
tmp_reg = ((1 << (SDIO_CSD1_CSIZE_MULT(res) + 2)) *
|
||||
( 1 << SDIO_CSD1_RBLKLEN(res))) >> 9;
|
||||
res->size = tmp_reg * (SDIO_CSD1_CSIZE(res) + 1);
|
||||
break;
|
||||
case 1:
|
||||
res->size = (SDIO_CSD2_CSIZE(res)+1) << 10;
|
||||
break;
|
||||
default:
|
||||
res->size = 0; // Bug if its not CSD V1 or V2
|
||||
}
|
||||
}
|
||||
|
||||
return (err == 0) ? res : NULL;
|
||||
}
|
||||
|
||||
static int stm32_sdio_card_detect(void)
|
||||
{
|
||||
SDIO_CARD sdcard;
|
||||
if (SD.card != NULL)
|
||||
return 0;
|
||||
sdcard = stm32_sdio_open(&SD);
|
||||
if (sdcard != NULL) {
|
||||
SD.card = sdcard;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sdcard_detect(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 20; i++) {
|
||||
if (stm32_sdio_card_detect() == 0)
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set up the GPIO pins and peripheral clocks for the SDIO
|
||||
* system. The code should probably take an option card detect
|
||||
* pin, at the moment it uses the one used by the Embest board.
|
||||
*/
|
||||
void sdcard_hw_init(void)
|
||||
{
|
||||
int i;
|
||||
uint32_t reg;
|
||||
/* Enable clocks for SDIO and DMA2 */
|
||||
APB2_CLOCK_ER |= SDIO_APB2_CLOCK_ER_VAL;
|
||||
/* Enable clocks for GPIOA, GPIOC, GPIOD */
|
||||
AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER |
|
||||
GPIOC_AHB1_CLOCK_ER | GPIOD_AHB1_CLOCK_ER;
|
||||
for (i = 0 ; i < 5; i++) {
|
||||
/* mode = AF */
|
||||
reg = GPIOC_MODE & ~ (0x03 << (sdio_pins[i] * 2));
|
||||
GPIOC_MODE = reg | (2 << (sdio_pins[i] * 2));
|
||||
|
||||
/* Alternate function: use high pins (8..12) */
|
||||
reg = GPIOC_AFH & ~(0xf << ((sdio_pins[i] - 8) * 4));
|
||||
GPIOC_AFH = reg | (sdio_af << ((sdio_pins[i] - 8) * 4));
|
||||
}
|
||||
/* cmd pin */
|
||||
reg = GPIOD_MODE & ~ (0x03 << (sdio_cmd_pin * 2));
|
||||
GPIOD_MODE = reg | (2 << (sdio_cmd_pin * 2));
|
||||
|
||||
/* Alternate function: use low pin */
|
||||
reg = GPIOD_AFL & ~(0xf << ((sdio_cmd_pin) * 4));
|
||||
GPIOD_AFL = reg | (sdio_af << ((sdio_cmd_pin) * 4));
|
||||
|
||||
/* card detect pin configured as input */
|
||||
GPIOA_MODE &= ~ (0x03 << (sdio_detect_pin * 2));
|
||||
reg = GPIOA_PUPD & (~(0x03 << (sdio_detect_pin & 2)));
|
||||
GPIOA_PUPD = reg | (1 << (sdio_detect_pin * 2));
|
||||
}
|
||||
|
||||
void *sdcard_open(void)
|
||||
{
|
||||
int ret;
|
||||
do {
|
||||
ret = stm32_sdio_card_detect();
|
||||
} while (ret < 0);
|
||||
return &SD;
|
||||
}
|
||||
|
||||
int sdcard_sense(void)
|
||||
{
|
||||
return !!(GPIOA_IDR & (1 << sdio_detect_pin));
|
||||
}
|
64
sdcard.h
Normal file
64
sdcard.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifndef SDCARD_INCLUDED
|
||||
#define SDCARD_INCLUDED
|
||||
#define SDIO_HAS_CARD_DETECT
|
||||
|
||||
enum SDIO_CLOCK_DIV {
|
||||
SDIO_24MHZ = 0,
|
||||
SDIO_16MHZ,
|
||||
SDIO_12MHZ,
|
||||
SDIO_8MHZ,
|
||||
SDIO_4MHZ,
|
||||
SDIO_1MHZ,
|
||||
SDIO_400KHZ
|
||||
};
|
||||
|
||||
enum SDIO_POWER_STATE {
|
||||
SDIO_POWER_ON,
|
||||
SDIO_POWER_OFF
|
||||
};
|
||||
|
||||
#define SDIO_CARD_CCS(c) (((c)->ocr & 0x40000000) != 0)
|
||||
#define SDIO_CARD_UHS2(c) (((c)->ocr & 0x40000000) != 0)
|
||||
#define SDIO_CARD_LVOK(c) (((c)->ocr & 0x01000000) != 0)
|
||||
|
||||
typedef struct SDIO_CARD_DATA {
|
||||
uint32_t props;
|
||||
uint32_t ocr;
|
||||
uint32_t cid[4];
|
||||
uint32_t csd[4];
|
||||
uint32_t scr[2];
|
||||
uint32_t status[16];
|
||||
uint32_t size;
|
||||
uint16_t rca;
|
||||
} * SDIO_CARD;
|
||||
|
||||
struct dev_sd {
|
||||
struct device *dev;
|
||||
uint32_t base;
|
||||
uint32_t *rcc_rst_reg;
|
||||
uint32_t rcc_rst;
|
||||
SDIO_CARD card;
|
||||
};
|
||||
|
||||
/* API for sd_bus clock setting */
|
||||
enum SD_CLOCK_DIV {
|
||||
CLOCK_24MHZ = 0,
|
||||
CLOCK_16MHZ,
|
||||
CLOCK_12MHZ,
|
||||
CLOCK_8MHZ,
|
||||
CLOCK_4MHZ,
|
||||
CLOCK_1MHZ,
|
||||
CLOCK_400KHZ
|
||||
};
|
||||
|
||||
//int stm32_sd_bus(int bits, enum SD_CLOCK_DIV freq);
|
||||
|
||||
void *sdcard_open(void);
|
||||
int sdcard_read(void *dev, void *_buf, uint32_t lba);
|
||||
int sdcard_write(void *dev, void *_buf, uint32_t lba);
|
||||
int sdcard_sense(void);
|
||||
int sdcard_detect(void);
|
||||
void sdcard_hw_init(void);
|
||||
|
||||
|
||||
#endif
|
105
spi.c
Normal file
105
spi.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "spi_drv.h"
|
||||
#include "system.h"
|
||||
|
||||
void spi_cs_off(void)
|
||||
{
|
||||
GPIOA_BSRR |= (1 << SPI_FLASH_PIN);
|
||||
DMB();
|
||||
while(!(GPIOA_ODR & (1 << SPI_FLASH_PIN)))
|
||||
;
|
||||
}
|
||||
|
||||
void spi_cs_on(void)
|
||||
{
|
||||
volatile int i;
|
||||
GPIOA_BSRR |= (1 << (SPI_FLASH_PIN + 16));
|
||||
DMB();
|
||||
while(GPIOA_ODR & (1 << SPI_FLASH_PIN))
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
static void spi_flash_pin_setup(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER;
|
||||
reg = GPIOA_MODE & ~ (0x03 << (SPI_FLASH_PIN * 2));
|
||||
GPIOA_MODE = reg | (1 << (SPI_FLASH_PIN * 2));
|
||||
|
||||
reg = GPIOA_PUPD & (0x03 << (SPI_FLASH_PIN * 2));
|
||||
GPIOA_PUPD = reg | (0x01 << (SPI_FLASH_PIN * 2));
|
||||
|
||||
reg = GPIOA_OSPD & ~(0x03 << (SPI_FLASH_PIN * 2));
|
||||
GPIOA_OSPD |= (0x03 << (SPI_FLASH_PIN * 2));
|
||||
|
||||
}
|
||||
|
||||
static void spi1_pins_setup(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER;
|
||||
/* Set mode = AF */
|
||||
reg = GPIOA_MODE & ~ (0x03 << (SPI1_CLOCK_PIN * 2));
|
||||
GPIOA_MODE = reg | (2 << (SPI1_CLOCK_PIN * 2));
|
||||
reg = GPIOA_MODE & ~ (0x03 << (SPI1_MOSI_PIN * 2));
|
||||
GPIOA_MODE = reg | (2 << (SPI1_MOSI_PIN * 2));
|
||||
reg = GPIOA_MODE & ~ (0x03 << (SPI1_MISO_PIN * 2));
|
||||
GPIOA_MODE = reg | (2 << (SPI1_MISO_PIN * 2));
|
||||
|
||||
/* Alternate function: use low pins (5,6,7) */
|
||||
reg = GPIOA_AFL & ~(0xf << ((SPI1_CLOCK_PIN) * 4));
|
||||
GPIOA_AFL = reg | (SPI1_PIN_AF << ((SPI1_CLOCK_PIN) * 4));
|
||||
reg = GPIOA_AFL & ~(0xf << ((SPI1_MOSI_PIN) * 4));
|
||||
GPIOA_AFL = reg | (SPI1_PIN_AF << ((SPI1_MOSI_PIN) * 4));
|
||||
reg = GPIOA_AFL & ~(0xf << ((SPI1_MISO_PIN) * 4));
|
||||
GPIOA_AFL = reg | (SPI1_PIN_AF << ((SPI1_MISO_PIN) * 4));
|
||||
|
||||
}
|
||||
|
||||
static void spi1_reset(void)
|
||||
{
|
||||
APB2_CLOCK_RST |= SPI1_APB2_CLOCK_ER_VAL;
|
||||
APB2_CLOCK_RST &= ~SPI1_APB2_CLOCK_ER_VAL;
|
||||
}
|
||||
|
||||
uint8_t spi_read(void)
|
||||
{
|
||||
volatile uint32_t reg;
|
||||
do {
|
||||
reg = SPI1_SR;
|
||||
} while(!(reg & SPI_SR_RX_NOTEMPTY));
|
||||
return (uint8_t)SPI1_DR;
|
||||
}
|
||||
|
||||
void spi_write(const char byte)
|
||||
{
|
||||
int i;
|
||||
volatile uint32_t reg;
|
||||
do {
|
||||
reg = SPI1_SR;
|
||||
} while ((reg & SPI_SR_TX_EMPTY) == 0);
|
||||
SPI1_DR = byte;
|
||||
do {
|
||||
reg = SPI1_SR;
|
||||
} while ((reg & SPI_SR_TX_EMPTY) == 0);
|
||||
}
|
||||
|
||||
|
||||
void spi_init(int polarity, int phase)
|
||||
{
|
||||
spi1_pins_setup();
|
||||
spi_flash_pin_setup();
|
||||
APB2_CLOCK_ER |= SPI1_APB2_CLOCK_ER_VAL;
|
||||
spi1_reset();
|
||||
SPI1_CR1 = SPI_CR1_MASTER | (5 << 3) | (polarity << 1) | (phase << 0);
|
||||
SPI1_CR2 |= SPI_CR2_SSOE;
|
||||
SPI1_CR1 |= SPI_CR1_SPI_EN;
|
||||
}
|
11
spi_drv.h
Normal file
11
spi_drv.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef SPI_DRV_H_INCLUDED
|
||||
#define SPI_DRV_H_INCLUDED
|
||||
#include <stdint.h>
|
||||
|
||||
void spi_init(int polarity, int phase);
|
||||
void spi_write(const char byte);
|
||||
uint8_t spi_read(void);
|
||||
void spi_cs_on(void);
|
||||
void spi_cs_off(void);
|
||||
|
||||
#endif
|
254
spi_flash.c
Normal file
254
spi_flash.c
Normal file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include "system.h"
|
||||
#include "spi_drv.h"
|
||||
|
||||
#define SPI_FLASH_SECTOR_SIZE (4096)
|
||||
#define SPI_FLASH_PAGE_SIZE (256)
|
||||
|
||||
#define MDID 0x90
|
||||
#define RDSR 0x05
|
||||
#define WRSR 0x01
|
||||
# define ST_BUSY (1 << 0)
|
||||
# define ST_WEL (1 << 1)
|
||||
# define ST_BP0 (1 << 2)
|
||||
# define ST_BP1 (1 << 3)
|
||||
# define ST_BP2 (1 << 4)
|
||||
# define ST_BP3 (1 << 5)
|
||||
# define ST_AAI (1 << 6)
|
||||
# define ST_BRO (1 << 7)
|
||||
#define WREN 0x06
|
||||
#define WRDI 0x04
|
||||
#define SECTOR_ERASE 0x20
|
||||
#define BYTE_READ 0x03
|
||||
#define BYTE_WRITE 0x02
|
||||
#define AUTOINC 0xAD
|
||||
#define EWSR 0x50
|
||||
#define EBSY 0x70
|
||||
#define DBSY 0x80
|
||||
|
||||
|
||||
static enum write_mode {
|
||||
WB_WRITEPAGE = 0x00,
|
||||
SST_AAI = 0x01
|
||||
} chip_write_mode = WB_WRITEPAGE;
|
||||
|
||||
static void write_address(uint32_t address)
|
||||
{
|
||||
spi_write((address & 0xFF00) >> 8);
|
||||
spi_read();
|
||||
spi_write((address & 0xFF0000) >> 16);
|
||||
spi_read();
|
||||
spi_write((address & 0xFF000000) >> 24);
|
||||
spi_read();
|
||||
}
|
||||
|
||||
static uint8_t read_status(void)
|
||||
{
|
||||
uint8_t status;
|
||||
int i;
|
||||
spi_cs_on();
|
||||
spi_write(RDSR);
|
||||
spi_read();
|
||||
spi_write(0xFF);
|
||||
status = spi_read();
|
||||
spi_cs_off();
|
||||
return status;
|
||||
}
|
||||
|
||||
static void spi_cmd(uint8_t cmd)
|
||||
{
|
||||
spi_cs_on();
|
||||
spi_write(cmd);
|
||||
spi_read();
|
||||
spi_cs_off();
|
||||
}
|
||||
|
||||
static inline void flash_aai_enable(void)
|
||||
{
|
||||
spi_cmd(EBSY);
|
||||
}
|
||||
|
||||
static inline void flash_aai_disable(void)
|
||||
{
|
||||
spi_cmd(DBSY);
|
||||
}
|
||||
|
||||
static void flash_write_enable(void)
|
||||
{
|
||||
uint8_t status;
|
||||
do {
|
||||
spi_cmd(WREN);
|
||||
status = read_status();
|
||||
} while ((status & ST_WEL) == 0);
|
||||
}
|
||||
|
||||
static void flash_write_disable(void)
|
||||
{
|
||||
uint8_t status;
|
||||
spi_cmd(WRDI);
|
||||
}
|
||||
static void wait_busy(void)
|
||||
{
|
||||
uint8_t status;
|
||||
do {
|
||||
status = read_status();
|
||||
} while(status & ST_BUSY);
|
||||
}
|
||||
|
||||
static int spi_flash_write_page(uint32_t address, const void *data, int len)
|
||||
{
|
||||
const uint8_t *buf = data;
|
||||
int j = 0;
|
||||
while (len > 0) {
|
||||
wait_busy();
|
||||
flash_write_enable();
|
||||
spi_cs_on();
|
||||
spi_write(BYTE_WRITE);
|
||||
spi_read();
|
||||
write_address(address);
|
||||
do {
|
||||
spi_write(buf[j++]);
|
||||
address++;
|
||||
spi_read();
|
||||
len--;
|
||||
} while ((address % SPI_FLASH_PAGE_SIZE) != 0);
|
||||
spi_cs_off();
|
||||
}
|
||||
wait_busy();
|
||||
return j;
|
||||
}
|
||||
|
||||
static int spi_flash_write_aai(uint32_t address, const void *data, int len)
|
||||
{
|
||||
const uint8_t *buf = data;
|
||||
int j = 0;
|
||||
int cont = 0;
|
||||
wait_busy();
|
||||
if (len < 1)
|
||||
return -1;
|
||||
while (len > 0) {
|
||||
if ((address & 0x01) || (len < 2)) {
|
||||
flash_write_enable();
|
||||
spi_cs_on();
|
||||
spi_write(BYTE_WRITE);
|
||||
spi_read();
|
||||
write_address(address);
|
||||
spi_write(buf[j++]);
|
||||
spi_read();
|
||||
spi_cs_off();
|
||||
len--;
|
||||
address++;
|
||||
} else {
|
||||
if (!cont) {
|
||||
flash_aai_enable();
|
||||
flash_write_enable();
|
||||
}
|
||||
spi_cs_on();
|
||||
spi_write(AUTOINC);
|
||||
spi_read();
|
||||
if (!cont) {
|
||||
/* First AAI transaction, send address. */
|
||||
write_address(address);
|
||||
cont = 1;
|
||||
}
|
||||
spi_write(buf[j++]);
|
||||
spi_read();
|
||||
spi_write(buf[j++]);
|
||||
spi_read();
|
||||
spi_cs_off();
|
||||
len -= 2;
|
||||
address += 2;
|
||||
read_status();
|
||||
}
|
||||
}
|
||||
if (cont) {
|
||||
flash_write_disable();
|
||||
flash_aai_disable();
|
||||
}
|
||||
wait_busy();
|
||||
return j;
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
uint16_t spi_flash_probe(void)
|
||||
{
|
||||
uint8_t manuf, product, b0;
|
||||
int i;
|
||||
wait_busy();
|
||||
spi_cs_on();
|
||||
spi_write(MDID);
|
||||
b0 = spi_read();
|
||||
|
||||
write_address(0);
|
||||
spi_write(0xFF);
|
||||
manuf = spi_read();
|
||||
spi_write(0xFF);
|
||||
product = spi_read();
|
||||
spi_cs_off();
|
||||
if (manuf == 0xBF)
|
||||
chip_write_mode = SST_AAI;
|
||||
if (manuf == 0xEF)
|
||||
chip_write_mode = WB_WRITEPAGE;
|
||||
|
||||
#ifndef READONLY
|
||||
spi_cmd(EWSR);
|
||||
spi_cs_on();
|
||||
spi_write(WRSR);
|
||||
spi_read();
|
||||
spi_write(0x00);
|
||||
spi_read();
|
||||
spi_cs_off();
|
||||
#endif
|
||||
return (uint16_t)(manuf << 8 | product);
|
||||
}
|
||||
|
||||
|
||||
void spi_flash_sector_erase(uint32_t address)
|
||||
{
|
||||
uint8_t status;
|
||||
address &= (~(SPI_FLASH_SECTOR_SIZE - 1));
|
||||
|
||||
wait_busy();
|
||||
flash_write_enable();
|
||||
spi_cs_on();
|
||||
spi_write(SECTOR_ERASE);
|
||||
spi_read();
|
||||
write_address(address);
|
||||
spi_cs_off();
|
||||
wait_busy();
|
||||
}
|
||||
|
||||
int spi_flash_read(uint32_t address, void *data, int len)
|
||||
{
|
||||
uint8_t *buf = data;
|
||||
int i = 0;
|
||||
wait_busy();
|
||||
spi_cs_on();
|
||||
spi_write(BYTE_READ);
|
||||
spi_read();
|
||||
write_address(address);
|
||||
while (len > 0) {
|
||||
spi_write(0xFF);
|
||||
buf[i++] = spi_read();
|
||||
len--;
|
||||
}
|
||||
spi_cs_off();
|
||||
return i;
|
||||
}
|
||||
|
||||
int spi_flash_write(uint32_t address, const void *data, int len)
|
||||
{
|
||||
if (chip_write_mode == SST_AAI)
|
||||
return spi_flash_write_aai(address, data, len);
|
||||
if (chip_write_mode == WB_WRITEPAGE)
|
||||
return spi_flash_write_page(address, data, len);
|
||||
return -1;
|
||||
}
|
||||
|
9
spi_flash.h
Normal file
9
spi_flash.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef SPI_FLASH_DRI_H
|
||||
#define SPI_FLASH_DRI_H
|
||||
#include <stdint.h>
|
||||
uint16_t spi_flash_probe(void);
|
||||
|
||||
void spi_flash_sector_erase(uint32_t address);
|
||||
int spi_flash_read(uint32_t address, void *data, int len);
|
||||
int spi_flash_write(uint32_t address, const void *data, int len);
|
||||
#endif
|
159
startup.c
Normal file
159
startup.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
|
||||
extern unsigned int _stored_data;
|
||||
extern unsigned int _start_data;
|
||||
extern unsigned int _end_data;
|
||||
extern unsigned int _start_bss;
|
||||
extern unsigned int _end_bss;
|
||||
extern unsigned int _end_stack;
|
||||
extern unsigned int _start_heap;
|
||||
|
||||
#define STACK_PAINTING
|
||||
|
||||
static volatile unsigned int avail_mem = 0;
|
||||
static unsigned int sp;
|
||||
|
||||
extern void main(void);
|
||||
extern void isr_exti(void);
|
||||
extern void isr_systick(void);
|
||||
|
||||
void isr_reset(void) {
|
||||
register unsigned int *src, *dst;
|
||||
src = (unsigned int *) &_stored_data;
|
||||
dst = (unsigned int *) &_start_data;
|
||||
/* Copy the .data section from flash to RAM. */
|
||||
while (dst < (unsigned int *)&_end_data) {
|
||||
*dst = *src;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
|
||||
/* Initialize the BSS section to 0 */
|
||||
dst = &_start_bss;
|
||||
while (dst < (unsigned int *)&_end_bss) {
|
||||
*dst = 0U;
|
||||
dst++;
|
||||
}
|
||||
|
||||
/* Paint the stack. */
|
||||
avail_mem = &_end_stack - &_start_heap;
|
||||
#ifdef STACK_PAINTING
|
||||
{
|
||||
asm volatile("mrs %0, msp" : "=r"(sp));
|
||||
dst = ((unsigned int *)(&_end_stack)) - (8192 / sizeof(unsigned int)); ;
|
||||
while ((unsigned int)dst < sp) {
|
||||
*dst = 0xDEADC0DE;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Run the program! */
|
||||
main();
|
||||
}
|
||||
|
||||
void isr_fault(void)
|
||||
{
|
||||
/* Panic. */
|
||||
while(1) ;;
|
||||
}
|
||||
|
||||
|
||||
void isr_memfault(void)
|
||||
{
|
||||
/* Panic. */
|
||||
while(1) ;;
|
||||
}
|
||||
|
||||
void isr_busfault(void)
|
||||
{
|
||||
/* Panic. */
|
||||
while(1) ;;
|
||||
}
|
||||
|
||||
void isr_usagefault(void)
|
||||
{
|
||||
/* Panic. */
|
||||
while(1) ;;
|
||||
}
|
||||
|
||||
|
||||
void isr_empty(void)
|
||||
{
|
||||
/* Ignore the event and continue */
|
||||
}
|
||||
|
||||
|
||||
|
||||
__attribute__ ((section(".isr_vector")))
|
||||
void (* const IV[])(void) =
|
||||
{
|
||||
(void (*)(void))(&_end_stack),
|
||||
isr_reset, // Reset
|
||||
isr_fault, // NMI
|
||||
isr_fault, // HardFault
|
||||
isr_memfault, // MemFault
|
||||
isr_busfault, // BusFault
|
||||
isr_usagefault, // UsageFault
|
||||
0, 0, 0, 0, // 4x reserved
|
||||
isr_empty, // SVC
|
||||
isr_empty, // DebugMonitor
|
||||
0, // reserved
|
||||
isr_empty, // PendSV
|
||||
isr_systick, // SysTick
|
||||
|
||||
isr_empty, // NVIC_WWDG_IRQ 0
|
||||
isr_empty, // PVD_IRQ 1
|
||||
isr_empty, // TAMP_STAMP_IRQ 2
|
||||
isr_empty, // RTC_WKUP_IRQ 3
|
||||
isr_empty, // FLASH_IRQ 4
|
||||
isr_empty, // RCC_IRQ 5
|
||||
isr_empty, // EXTI0_IRQ 6
|
||||
isr_empty, // EXTI1_IRQ 7
|
||||
isr_empty, // EXTI2_IRQ 8
|
||||
isr_empty, // EXTI3_IRQ 9
|
||||
isr_empty, // EXTI4_IRQ 10
|
||||
isr_empty, // DMA1_STREAM0_IRQ 11
|
||||
isr_empty, // DMA1_STREAM1_IRQ 12
|
||||
isr_empty, // DMA1_STREAM2_IRQ 13
|
||||
isr_empty, // DMA1_STREAM3_IRQ 14
|
||||
isr_empty, // DMA1_STREAM4_IRQ 15
|
||||
isr_empty, // DMA1_STREAM5_IRQ 16
|
||||
isr_empty, // DMA1_STREAM6_IRQ 17
|
||||
isr_empty, // ADC_IRQ 18
|
||||
isr_empty, // CAN1_TX_IRQ 19
|
||||
isr_empty, // CAN1_RX0_IRQ 20
|
||||
isr_empty, // CAN1_RX1_IRQ 21
|
||||
isr_empty, // CAN1_SCE_IRQ 22
|
||||
isr_empty, // EXTI9_5_IRQ 23
|
||||
isr_empty, // TIM1_BRK_TIM9_IRQ 24
|
||||
isr_empty, // TIM1_UP_TIM10_IRQ 25
|
||||
isr_empty, // TIM1_TRG_COM_TIM11_IRQ 26
|
||||
isr_empty, // TIM1_CC_IRQ 27
|
||||
isr_empty, // TIM2_IRQ 28
|
||||
isr_empty, // TIM3_IRQ 29
|
||||
isr_empty, // TIM4_IRQ 30
|
||||
isr_empty, // I2C1_EV_IRQ 31
|
||||
isr_empty, // I2C1_ER_IRQ 32
|
||||
isr_empty, // I2C2_EV_IRQ 33
|
||||
isr_empty, // I2C2_ER_IRQ 34
|
||||
isr_empty, // SPI1_IRQ 35
|
||||
isr_empty, // SPI2_IRQ 36
|
||||
isr_empty, // USART1_IRQ 37
|
||||
isr_empty, // USART2_IRQ 38
|
||||
isr_empty, // USART3_IRQ 39
|
||||
isr_exti, // EXTI15_10_IRQ 40
|
||||
isr_empty, // RTC_ALARM_IRQ 41
|
||||
isr_empty, // USB_FS_WKUP_IRQ 42
|
||||
isr_empty, // TIM8_BRK_TIM12_IRQ 43
|
||||
isr_empty, // TIM8_UP_TIM13_IRQ 44
|
||||
isr_empty, // TIM8_TRG_COM_TIM14_IRQ 45
|
||||
isr_empty, // TIM8_CC_IRQ 46
|
||||
isr_empty, // DMA1_STREAM7_IRQ 47
|
||||
|
||||
};
|
177
system.c
Normal file
177
system.c
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "system.h"
|
||||
|
||||
uint32_t cpu_freq = 84000000;
|
||||
/*** FLASH ***/
|
||||
#define FLASH_BASE (0x40023C00)
|
||||
#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00))
|
||||
#define FLASH_ACR_ENABLE_DATA_CACHE (1 << 10)
|
||||
#define FLASH_ACR_ENABLE_INST_CACHE (1 << 9)
|
||||
|
||||
static void flash_set_waitstates(int waitstates)
|
||||
{
|
||||
FLASH_ACR |= waitstates | FLASH_ACR_ENABLE_DATA_CACHE | FLASH_ACR_ENABLE_INST_CACHE;
|
||||
}
|
||||
/*** RCC ***/
|
||||
|
||||
#define RCC_BASE (0x40023800)
|
||||
#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00))
|
||||
#define RCC_PLLCFGR (*(volatile uint32_t *)(RCC_BASE + 0x04))
|
||||
#define RCC_CFGR (*(volatile uint32_t *)(RCC_BASE + 0x08))
|
||||
#define RCC_CR_PLLRDY (1 << 25)
|
||||
#define RCC_CR_PLLON (1 << 24)
|
||||
#define RCC_CR_HSERDY (1 << 17)
|
||||
#define RCC_CR_HSEON (1 << 16)
|
||||
#define RCC_CR_HSIRDY (1 << 1)
|
||||
#define RCC_CR_HSION (1 << 0)
|
||||
|
||||
#define RCC_CFGR_SW_HSI 0x0
|
||||
#define RCC_CFGR_SW_HSE 0x1
|
||||
#define RCC_CFGR_SW_PLL 0x2
|
||||
|
||||
|
||||
#define RCC_PLLCFGR_PLLSRC (1 << 22)
|
||||
|
||||
#define RCC_PRESCALER_DIV_NONE 0
|
||||
#define RCC_PRESCALER_DIV_2 8
|
||||
#define RCC_PRESCALER_DIV_4 9
|
||||
|
||||
|
||||
void clock_pll_off(void)
|
||||
{
|
||||
uint32_t reg32;
|
||||
/* Enable internal high-speed oscillator. */
|
||||
RCC_CR |= RCC_CR_HSION;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_HSIRDY) == 0) {};
|
||||
|
||||
/* Select HSI as SYSCLK source. */
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~((1 << 1) | (1 << 0));
|
||||
RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI);
|
||||
DMB();
|
||||
|
||||
/* Turn off PLL */
|
||||
RCC_CR &= ~RCC_CR_PLLON;
|
||||
DMB();
|
||||
}
|
||||
|
||||
|
||||
void clock_pll_on(int powersave)
|
||||
{
|
||||
uint32_t reg32;
|
||||
uint32_t plln, pllm, pllq, pllp, pllr, hpre, ppre1, ppre2, flash_waitstates;
|
||||
|
||||
/* Enable Power controller */
|
||||
APB1_CLOCK_ER |= PWR_APB1_CLOCK_ER_VAL;
|
||||
|
||||
/* Select clock parameters */
|
||||
cpu_freq = 84000000 ;
|
||||
pllm = 12;
|
||||
plln = 336;
|
||||
pllp = 4;
|
||||
pllq = 7;
|
||||
pllr = 0;
|
||||
hpre = RCC_PRESCALER_DIV_NONE;
|
||||
ppre1 = RCC_PRESCALER_DIV_2;
|
||||
ppre2 = RCC_PRESCALER_DIV_NONE;
|
||||
flash_waitstates = 2;
|
||||
|
||||
flash_set_waitstates(flash_waitstates);
|
||||
|
||||
/* Enable internal high-speed oscillator. */
|
||||
RCC_CR |= RCC_CR_HSION;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_HSIRDY) == 0) {};
|
||||
|
||||
/* Select HSI as SYSCLK source. */
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~((1 << 1) | (1 << 0));
|
||||
RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI);
|
||||
DMB();
|
||||
|
||||
/* Enable external high-speed oscillator 12MHz. */
|
||||
RCC_CR |= RCC_CR_HSEON;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_HSERDY) == 0) {};
|
||||
|
||||
/*
|
||||
* Set prescalers for AHB, ADC, ABP1, ABP2.
|
||||
*/
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(0xF0);
|
||||
RCC_CFGR = (reg32 | (hpre << 4));
|
||||
DMB();
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(0x1C00);
|
||||
RCC_CFGR = (reg32 | (ppre1 << 10));
|
||||
DMB();
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(0x07 << 13);
|
||||
RCC_CFGR = (reg32 | (ppre2 << 13));
|
||||
DMB();
|
||||
|
||||
/* Set PLL config */
|
||||
reg32 = RCC_PLLCFGR;
|
||||
reg32 &= ~(PLL_FULL_MASK);
|
||||
RCC_PLLCFGR = reg32 | RCC_PLLCFGR_PLLSRC | pllm |
|
||||
(plln << 6) | (((pllp >> 1) - 1) << 16) |
|
||||
(pllq << 24);
|
||||
DMB();
|
||||
|
||||
/* Enable power-save mode if selected */
|
||||
if (powersave) {
|
||||
POW_CR |= (POW_CR_VOS);
|
||||
}
|
||||
|
||||
/* Enable PLL oscillator and wait for it to stabilize. */
|
||||
RCC_CR |= RCC_CR_PLLON;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_PLLRDY) == 0) {};
|
||||
|
||||
/* Select PLL as SYSCLK source. */
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~((1 << 1) | (1 << 0));
|
||||
RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL);
|
||||
DMB();
|
||||
|
||||
/* Wait for PLL clock to be selected. */
|
||||
while (((RCC_CFGR & ((1 << 3) | (1 << 2))) >> 2) != RCC_CFGR_SW_PLL) {};
|
||||
|
||||
/* Disable internal high-speed oscillator. */
|
||||
RCC_CR &= ~RCC_CR_HSION;
|
||||
}
|
||||
|
||||
void *__attribute__((weak)) memcpy(void *d, void *s, uint32_t len)
|
||||
{
|
||||
uint32_t *src, *dst;
|
||||
uint8_t *sb, *db;
|
||||
src = s;
|
||||
dst = d;
|
||||
while(len > 3) {
|
||||
*(dst++) = *(src++);
|
||||
len -= 4;
|
||||
}
|
||||
sb = (uint8_t *)src;
|
||||
db = (uint8_t *)dst;
|
||||
while(len > 0) {
|
||||
*(db++) = *(sb++);
|
||||
len--;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
void panic(void)
|
||||
{
|
||||
printf("PANIC!");
|
||||
while(1)
|
||||
;
|
||||
}
|
||||
|
430
system.h
Normal file
430
system.h
Normal file
|
@ -0,0 +1,430 @@
|
|||
#ifndef SYSTEM_H_INCLUDED
|
||||
#define SYSTEM_H_INCLUDED
|
||||
#include <stdint.h>
|
||||
/* System specific: PLL with 8 MHz external oscillator, CPU at 168MHz */
|
||||
#define PLL_FULL_MASK (0x7F037FFF)
|
||||
extern uint32_t cpu_freq;
|
||||
void panic(void);
|
||||
|
||||
|
||||
/* PIN CONFIG TARGET */
|
||||
#define BLUE_LED 4
|
||||
#define RED_LED 13
|
||||
#define GREEN_LED 14
|
||||
#define YELLOW_LED 15
|
||||
|
||||
#define SPI_FLASH_PIN 4 /* Flash CS connected to GPIOA4 */
|
||||
#define SPI1_PIN_AF 5
|
||||
#define SPI1_CLOCK_PIN 5
|
||||
#define SPI1_MISO_PIN 6
|
||||
#define SPI1_MOSI_PIN 7
|
||||
|
||||
#define SPI2_PIN_AF 5
|
||||
#define SPI2_CLOCK_PIN 13
|
||||
#define SPI2_MISO_PIN 14
|
||||
#define SPI2_MOSI_PIN 15
|
||||
|
||||
|
||||
#define I2C1_PIN_AF 4
|
||||
#define I2C1_SDA 7 /* GPIOB P7 */
|
||||
#define I2C1_SCL 6 /* GPIOB P6 */
|
||||
#define GPIO_MODE_AF (2)
|
||||
|
||||
|
||||
/* STM32 specific defines */
|
||||
#define APB1_CLOCK_ER (*(volatile uint32_t *)(0x40023840))
|
||||
#define APB1_CLOCK_RST (*(volatile uint32_t *)(0x40023820))
|
||||
#define TIM2_APB1_CLOCK_ER_VAL (1 << 0)
|
||||
#define PWR_APB1_CLOCK_ER_VAL (1 << 28)
|
||||
#define SPI2_APB1_CLOCK_ER_VAL (1 << 14)
|
||||
|
||||
#define APB2_CLOCK_ER (*(volatile uint32_t *)(0x40023844))
|
||||
#define APB2_CLOCK_RST (*(volatile uint32_t *)(0x40023824))
|
||||
#define SYSCFG_APB2_CLOCK_ER (1 << 14)
|
||||
#define SPI1_APB2_CLOCK_ER_VAL (1 << 12)
|
||||
#define SDIO_APB2_CLOCK_ER_VAL (1 << 11)
|
||||
|
||||
#define RCC_BACKUP (*(volatile uint32_t *)(0x40023870))
|
||||
#define RCC_BACKUP_RESET (1 << 16)
|
||||
#define RCC_BACKUP_RTCEN (1 << 15)
|
||||
#define RCC_BACKUP_RTCSEL_SHIFT 8
|
||||
#define RCC_BACKUP_RTCSEL_MASK 0x3
|
||||
#define RCC_BACKUP_RTCSEL_NONE 0
|
||||
#define RCC_BACKUP_RTCSEL_LSE 1
|
||||
#define RCC_BACKUP_RTCSEL_LSI 2
|
||||
#define RCC_BACKUP_RTCSEL_HSE 3
|
||||
#define RCC_BACKUP_LSEMOD (1 << 3)
|
||||
#define RCC_BACKUP_LSEBYP (1 << 2)
|
||||
#define RCC_BACKUP_LSERDY (1 << 1)
|
||||
#define RCC_BACKUP_LSEON (1 << 0)
|
||||
|
||||
#define RCC_CSR_LSION (1 << 0)
|
||||
#define RCC_CSR_LSIRDY (1 << 1)
|
||||
|
||||
/* EXTI */
|
||||
#define EXTI_CR_BASE (0x40013808)
|
||||
#define EXTI_CR0 (*(volatile uint32_t *)(EXTI_CR_BASE + 0x00))
|
||||
#define EXTI_CR_EXTI0_MASK (0xFFFF)
|
||||
|
||||
#define EXTI_IMR (*(volatile uint32_t *)(EXTI_BASE + 0x00))
|
||||
#define EXTI_EMR (*(volatile uint32_t *)(EXTI_BASE + 0x04))
|
||||
#define EXTI_RTSR (*(volatile uint32_t *)(EXTI_BASE + 0x08))
|
||||
#define EXTI_FTSR (*(volatile uint32_t *)(EXTI_BASE + 0x0c))
|
||||
#define EXTI_SWIER (*(volatile uint32_t *)(EXTI_BASE + 0x10))
|
||||
#define EXTI_PR (*(volatile uint32_t *)(EXTI_BASE + 0x14))
|
||||
|
||||
|
||||
/* HW RNG */
|
||||
#define RNG_BASE (0x50060800)
|
||||
#define RNG_CR (*(volatile uint32_t *)(RNG_BASE + 0x00))
|
||||
#define RNG_SR (*(volatile uint32_t *)(RNG_BASE + 0x04))
|
||||
#define RNG_DR (*(volatile uint32_t *)(RNG_BASE + 0x08))
|
||||
|
||||
#define RNG_CR_IE (1 << 3)
|
||||
#define RNG_CR_RNGEN (1 << 2)
|
||||
|
||||
#define RNG_SR_DRDY (1 << 0)
|
||||
#define RNG_SR_CECS (1 << 1)
|
||||
#define RNG_SR_SECS (1 << 2)
|
||||
|
||||
|
||||
/* SCB for sleep configuration */
|
||||
#define SCB_SCR (*(volatile uint32_t *)(0xE000ED10))
|
||||
#define SCB_SCR_SEVONPEND (1 << 4)
|
||||
#define SCB_SCR_SLEEPDEEP (1 << 2)
|
||||
#define SCB_SCR_SLEEPONEXIT (1 << 1)
|
||||
|
||||
/* Assembly helpers */
|
||||
#define DMB() __asm__ volatile ("dmb")
|
||||
#define WFI() __asm__ volatile ("wfi")
|
||||
#define WFE() __asm__ volatile ("wfe")
|
||||
#define SEV() __asm__ volatile ("sev")
|
||||
|
||||
/* Master clock setting */
|
||||
void clock_pll_on(int powersave);
|
||||
void clock_pll_off(void);
|
||||
|
||||
|
||||
/* NVIC */
|
||||
/* NVIC ISER Base register (Cortex-M) */
|
||||
#define NVIC_RTC_IRQ (3)
|
||||
#define NVIC_EXTI0_IRQN (6)
|
||||
#define NVIC_TIM2_IRQN (28)
|
||||
#define NVIC_ISER_BASE (0xE000E100)
|
||||
#define NVIC_ICER_BASE (0xE000E180)
|
||||
#define NVIC_ICPR_BASE (0xE000E280)
|
||||
#define NVIC_IPRI_BASE (0xE000E400)
|
||||
#define NVIC_EXTI15_10_IRQ (40)
|
||||
|
||||
static inline void nvic_irq_enable(uint8_t n)
|
||||
{
|
||||
int i = n / 32;
|
||||
volatile uint32_t *nvic_iser = ((volatile uint32_t *)(NVIC_ISER_BASE + 4 * i));
|
||||
*nvic_iser |= (1 << (n % 32));
|
||||
}
|
||||
|
||||
static inline void nvic_irq_disable(uint8_t n)
|
||||
{
|
||||
int i = n / 32;
|
||||
volatile uint32_t *nvic_icer = ((volatile uint32_t *)(NVIC_ICER_BASE + 4 * i));
|
||||
*nvic_icer |= (1 << (n % 32));
|
||||
}
|
||||
|
||||
static inline void nvic_irq_setprio(uint8_t n, uint8_t prio)
|
||||
{
|
||||
volatile uint8_t *nvic_ipri = ((volatile uint8_t *)(NVIC_IPRI_BASE + n));
|
||||
*nvic_ipri = prio;
|
||||
}
|
||||
|
||||
|
||||
static inline void nvic_irq_clear(uint8_t n)
|
||||
{
|
||||
int i = n / 32;
|
||||
volatile uint8_t *nvic_icpr = ((volatile uint8_t *)(NVIC_ICPR_BASE + 4 * i));
|
||||
*nvic_icpr = (1 << (n % 32));
|
||||
}
|
||||
/*** FLASH ***/
|
||||
#define FLASH_BASE (0x40023C00)
|
||||
#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00))
|
||||
#define FLASH_ACR_ENABLE_DATA_CACHE (1 << 10)
|
||||
#define FLASH_ACR_ENABLE_INST_CACHE (1 << 9)
|
||||
|
||||
/*** SPI ***/
|
||||
#define SPI1 (0x40013000)
|
||||
#define SPI1_CR1 (*(volatile uint32_t *)(SPI1))
|
||||
#define SPI1_CR2 (*(volatile uint32_t *)(SPI1 + 0x04))
|
||||
#define SPI1_SR (*(volatile uint32_t *)(SPI1 + 0x08))
|
||||
#define SPI1_DR (*(volatile uint32_t *)(SPI1 + 0x0c))
|
||||
|
||||
#define SPI2 (0x40003800)
|
||||
#define SPI2_CR1 (*(volatile uint32_t *)(SPI2))
|
||||
#define SPI2_CR2 (*(volatile uint32_t *)(SPI2 + 0x04))
|
||||
#define SPI2_SR (*(volatile uint32_t *)(SPI2 + 0x08))
|
||||
#define SPI2_DR (*(volatile uint32_t *)(SPI2 + 0x0c))
|
||||
|
||||
|
||||
#define SPI_CR1_CLOCK_PHASE (1 << 0)
|
||||
#define SPI_CR1_CLOCK_POLARITY (1 << 1)
|
||||
#define SPI_CR1_MASTER (1 << 2)
|
||||
#define SPI_CR1_BAUDRATE (0x07 << 3)
|
||||
#define SPI_CR1_SPI_EN (1 << 6)
|
||||
#define SPI_CR1_LSBFIRST (1 << 7)
|
||||
#define SPI_CR1_SSI (1 << 8)
|
||||
#define SPI_CR1_SSM (1 << 9)
|
||||
#define SPI_CR1_16BIT_FORMAT (1 << 11)
|
||||
#define SPI_CR1_TX_CRC_NEXT (1 << 12)
|
||||
#define SPI_CR1_HW_CRC_EN (1 << 13)
|
||||
#define SPI_CR1_BIDIOE (1 << 14)
|
||||
#define SPI_CR2_SSOE (1 << 2)
|
||||
|
||||
|
||||
|
||||
#define SPI_SR_RX_NOTEMPTY (1 << 0)
|
||||
#define SPI_SR_TX_EMPTY (1 << 1)
|
||||
#define SPI_SR_BUSY (1 << 7)
|
||||
|
||||
|
||||
/*** RCC ***/
|
||||
|
||||
#define RCC_CR_PLLRDY (1 << 25)
|
||||
#define RCC_CR_PLLON (1 << 24)
|
||||
#define RCC_CR_HSERDY (1 << 17)
|
||||
#define RCC_CR_HSEON (1 << 16)
|
||||
#define RCC_CR_HSIRDY (1 << 1)
|
||||
#define RCC_CR_HSION (1 << 0)
|
||||
|
||||
#define RCC_CFGR_SW_HSI 0x0
|
||||
#define RCC_CFGR_SW_HSE 0x1
|
||||
#define RCC_CFGR_SW_PLL 0x2
|
||||
|
||||
#define RCC_PRESCALER_DIV_NONE 0
|
||||
#define RCC_PRESCALER_DIV_2 8
|
||||
#define RCC_PRESCALER_DIV_4 9
|
||||
|
||||
|
||||
#define RCC_PLLCFGR_PLLSRC (1 << 22)
|
||||
#define AHB1_CLOCK_ER (*(volatile uint32_t *)(0x40023830))
|
||||
#define GPIOA_AHB1_CLOCK_ER (1 << 0)
|
||||
#define GPIOB_AHB1_CLOCK_ER (1 << 1)
|
||||
#define GPIOC_AHB1_CLOCK_ER (1 << 2)
|
||||
#define GPIOD_AHB1_CLOCK_ER (1 << 3)
|
||||
#define GPIOE_AHB1_CLOCK_ER (1 << 4)
|
||||
#define GPIOA_BASE 0x40020000
|
||||
#define GPIOB_BASE 0x40020400
|
||||
#define GPIOC_BASE 0x40020800
|
||||
#define GPIOD_BASE 0x40020C00
|
||||
#define GPIOE_BASE 0x40021000
|
||||
|
||||
#define AHB2_CLOCK_ER (*(volatile uint32_t *)(0x40023834))
|
||||
#define RNG_AHB2_CLOCK_ER (1 << 6)
|
||||
|
||||
|
||||
/* POWER CONTROL REGISTER */
|
||||
#define POW_BASE (0x40007000)
|
||||
#define POW_CR (*(volatile uint32_t *)(POW_BASE + 0x00))
|
||||
#define POW_SCR (*(volatile uint32_t *)(POW_BASE + 0x04))
|
||||
|
||||
#define POW_CR_VOS (1 << 14)
|
||||
#define POW_CR_FPDS (1 << 9)
|
||||
#define POW_CR_DPB (1 << 8)
|
||||
#define POW_CR_CSBF (1 << 3)
|
||||
#define POW_CR_CWUF (1 << 2)
|
||||
#define POW_CR_PDDS (1 << 1)
|
||||
#define POW_CR_LPDS (1 << 0)
|
||||
#define POW_SCR_BRE (1 << 9)
|
||||
#define POW_SCR_EWUP (1 << 4)
|
||||
#define POW_SCR_BRR (1 << 3)
|
||||
#define POW_SCR_WUF (1 << 0)
|
||||
|
||||
|
||||
|
||||
/* GPIOS */
|
||||
|
||||
|
||||
#define GPIOA_MODE (*(volatile uint32_t *)(GPIOA_BASE + 0x00))
|
||||
#define GPIOA_AFL (*(volatile uint32_t *)(GPIOA_BASE + 0x20))
|
||||
#define GPIOA_AFH (*(volatile uint32_t *)(GPIOA_BASE + 0x24))
|
||||
#define GPIOA_OSPD (*(volatile uint32_t *)(GPIOA_BASE + 0x08))
|
||||
#define GPIOA_PUPD (*(volatile uint32_t *)(GPIOA_BASE + 0x0c))
|
||||
#define GPIOA_BSRR (*(volatile uint32_t *)(GPIOA_BASE + 0x18))
|
||||
#define GPIOA_ODR (*(volatile uint32_t *)(GPIOA_BASE + 0x14))
|
||||
#define GPIOA_IDR (*(volatile uint32_t *)(GPIOA_BASE + 0x10))
|
||||
|
||||
#define GPIOB_MODE (*(volatile uint32_t *)(GPIOB_BASE + 0x00))
|
||||
#define GPIOB_AFL (*(volatile uint32_t *)(GPIOB_BASE + 0x20))
|
||||
#define GPIOB_AFH (*(volatile uint32_t *)(GPIOB_BASE + 0x24))
|
||||
#define GPIOB_OSPD (*(volatile uint32_t *)(GPIOB_BASE + 0x08))
|
||||
#define GPIOB_PUPD (*(volatile uint32_t *)(GPIOB_BASE + 0x0c))
|
||||
#define GPIOB_BSRR (*(volatile uint32_t *)(GPIOB_BASE + 0x18))
|
||||
#define GPIOB_ODR (*(volatile uint32_t *)(GPIOB_BASE + 0x14))
|
||||
|
||||
#define GPIOC_MODE (*(volatile uint32_t *)(GPIOC_BASE + 0x00))
|
||||
#define GPIOC_OTYPE (*(volatile uint32_t *)(GPIOC_BASE + 0x04))
|
||||
#define GPIOC_OSPEED (*(volatile uint32_t *)(GPIOC_BASE + 0x08))
|
||||
#define GPIOC_AFL (*(volatile uint32_t *)(GPIOC_BASE + 0x20))
|
||||
#define GPIOC_AFH (*(volatile uint32_t *)(GPIOC_BASE + 0x24))
|
||||
#define GPIOC_OSPD (*(volatile uint32_t *)(GPIOC_BASE + 0x08))
|
||||
#define GPIOC_PUPD (*(volatile uint32_t *)(GPIOC_BASE + 0x0c))
|
||||
#define GPIOC_BSRR (*(volatile uint32_t *)(GPIOC_BASE + 0x18))
|
||||
#define GPIOC_ODR (*(volatile uint32_t *)(GPIOC_BASE + 0x14))
|
||||
|
||||
|
||||
#define GPIOD_MODE (*(volatile uint32_t *)(GPIOD_BASE + 0x00))
|
||||
#define GPIOD_OTYPE (*(volatile uint32_t *)(GPIOD_BASE + 0x04))
|
||||
#define GPIOD_OSPEED (*(volatile uint32_t *)(GPIOD_BASE + 0x08))
|
||||
#define GPIOD_AFL (*(volatile uint32_t *)(GPIOD_BASE + 0x20))
|
||||
#define GPIOD_AFH (*(volatile uint32_t *)(GPIOD_BASE + 0x24))
|
||||
#define GPIOD_OSPD (*(volatile uint32_t *)(GPIOD_BASE + 0x08))
|
||||
#define GPIOD_PUPD (*(volatile uint32_t *)(GPIOD_BASE + 0x0c))
|
||||
#define GPIOD_BSRR (*(volatile uint32_t *)(GPIOD_BASE + 0x18))
|
||||
#define GPIOD_ODR (*(volatile uint32_t *)(GPIOD_BASE + 0x14))
|
||||
|
||||
#define GPIOE_MODE (*(volatile uint32_t *)(GPIOE_BASE + 0x00))
|
||||
#define GPIOE_AFL (*(volatile uint32_t *)(GPIOE_BASE + 0x20))
|
||||
#define GPIOE_AFH (*(volatile uint32_t *)(GPIOE_BASE + 0x24))
|
||||
#define GPIOE_OSPD (*(volatile uint32_t *)(GPIOE_BASE + 0x08))
|
||||
#define GPIOE_PUPD (*(volatile uint32_t *)(GPIOE_BASE + 0x0c))
|
||||
#define GPIOE_BSRR (*(volatile uint32_t *)(GPIOE_BASE + 0x18))
|
||||
#define GPIOE_ODR (*(volatile uint32_t *)(GPIOE_BASE + 0x14))
|
||||
#define GPIO_MODE_AF (2)
|
||||
|
||||
/* SDIO */
|
||||
#define SDIO_BASE (0x40012C00)
|
||||
#define SDIO_POWER (*(volatile uint32_t *)((SDIO_BASE) + 0x00))
|
||||
#define SDIO_CLKCR (*(volatile uint32_t *)((SDIO_BASE) + 0x04))
|
||||
#define SDIO_ARG (*(volatile uint32_t *)((SDIO_BASE) + 0x08))
|
||||
#define SDIO_CMD (*(volatile uint32_t *)((SDIO_BASE) + 0x0C))
|
||||
#define SDIO_RESPCMD (*(volatile uint32_t *)((SDIO_BASE) + 0x10))
|
||||
#define SDIO_RESP1 (*(volatile uint32_t *)((SDIO_BASE) + 0x14))
|
||||
#define SDIO_RESP2 (*(volatile uint32_t *)((SDIO_BASE) + 0x18))
|
||||
#define SDIO_RESP3 (*(volatile uint32_t *)((SDIO_BASE) + 0x1C))
|
||||
#define SDIO_RESP4 (*(volatile uint32_t *)((SDIO_BASE) + 0x20))
|
||||
#define SDIO_DTIMER (*(volatile uint32_t *)((SDIO_BASE) + 0x24))
|
||||
#define SDIO_DLEN (*(volatile uint32_t *)((SDIO_BASE) + 0x28))
|
||||
#define SDIO_DCTRL (*(volatile uint32_t *)((SDIO_BASE) + 0x2C))
|
||||
#define SDIO_DCOUNT (*(volatile uint32_t *)((SDIO_BASE) + 0x30))
|
||||
#define SDIO_STA (*(volatile uint32_t *)((SDIO_BASE) + 0x34))
|
||||
#define SDIO_ICR (*(volatile uint32_t *)((SDIO_BASE) + 0x38))
|
||||
#define SDIO_MASK (*(volatile uint32_t *)((SDIO_BASE) + 0x3C))
|
||||
#define SDIO_FIFOCNT (*(volatile uint32_t *)((SDIO_BASE) + 0x48))
|
||||
#define SDIO_FIFO (*(volatile uint32_t *)((SDIO_BASE) + 0x80))
|
||||
|
||||
#define SDIO_POWER_PWRCTRL_SHIFT 0
|
||||
#define SDIO_POWER_PWRCTRL_PWROFF (0x0 << SDIO_POWER_PWRCTRL_SHIFT)
|
||||
#define SDIO_POWER_PWRCTRL_RSVPWRUP (0x2 << SDIO_POWER_PWRCTRL_SHIFT)
|
||||
#define SDIO_POWER_PWRCTRL_PWRON (0x3 << SDIO_POWER_PWRCTRL_SHIFT)
|
||||
#define SDIO_CLKCR_HWFC_EN (1 << 14)
|
||||
#define SDIO_CLKCR_NEGEDGE (1 << 13)
|
||||
#define SDIO_CLKCR_WIDBUS_SHIFT 11
|
||||
#define SDIO_CLKCR_WIDBUS_1 (0x0 << SDIO_CLKCR_WIDBUS_SHIFT)
|
||||
#define SDIO_CLKCR_WIDBUS_4 (0x1 << SDIO_CLKCR_WIDBUS_SHIFT)
|
||||
#define SDIO_CLKCR_WIDBUS_8 (0x2 << SDIO_CLKCR_WIDBUS_SHIFT)
|
||||
#define SDIO_CLKCR_BYPASS (1 << 10)
|
||||
#define SDIO_CLKCR_PWRSAV (1 << 9)
|
||||
#define SDIO_CLKCR_CLKEN (1 << 8)
|
||||
#define SDIO_CLKCR_CLKDIV_SHIFT 0
|
||||
#define SDIO_CLKCR_CLKDIV_MSK (0xFF << SDIO_CLKCR_CLKDIV_SHIFT)
|
||||
#define SDIO_CMD_ATACMD (1 << 14)
|
||||
#define SDIO_CMD_NIEN (1 << 13)
|
||||
#define SDIO_CMD_ENCMDCOMPL (1 << 12)
|
||||
#define SDIO_CMD_SDIOSUSPEND (1 << 11)
|
||||
#define SDIO_CMD_CPSMEN (1 << 10)
|
||||
#define SDIO_CMD_WAITPEND (1 << 9)
|
||||
#define SDIO_CMD_WAITINT (1 << 8)
|
||||
#define SDIO_CMD_WAITRESP_SHIFT 6
|
||||
#define SDIO_CMD_WAITRESP_NO_0 (0x0 << SDIO_CMD_WAITRESP_SHIFT)
|
||||
#define SDIO_CMD_WAITRESP_SHORT (0x1 << SDIO_CMD_WAITRESP_SHIFT)
|
||||
#define SDIO_CMD_WAITRESP_NO_2 (0x2 << SDIO_CMD_WAITRESP_SHIFT)
|
||||
#define SDIO_CMD_WAITRESP_LONG (0x3 << SDIO_CMD_WAITRESP_SHIFT)
|
||||
#define SDIO_CMD_CMDINDEX_SHIFT 0
|
||||
#define SDIO_CMD_CMDINDEX_MSK (0x3F << SDIO_CMD_CMDINDEX_SHIFT)
|
||||
#define SDIO_RESPCMD_SHIFT 0
|
||||
#define SDIO_RESPCMD_MSK (0x3F << SDIO_RESPCMD_SHIFT)
|
||||
#define SDIO_DCTRL_SDIOEN (1 << 11)
|
||||
#define SDIO_DCTRL_RWMOD (1 << 10)
|
||||
#define SDIO_DCTRL_RWSTOP (1 << 9)
|
||||
#define SDIO_DCTRL_RWSTART (1 << 8)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_SHIFT 4
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_0 (0x0 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_1 (0x1 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_2 (0x2 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_3 (0x3 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_4 (0x4 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_5 (0x5 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_6 (0x6 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_7 (0x7 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_8 (0x8 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_9 (0x9 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_10 (0xA << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_11 (0xB << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_12 (0xC << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_13 (0xD << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DBLOCKSIZE_14 (0xE << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
|
||||
#define SDIO_DCTRL_DMAEN (1 << 3)
|
||||
#define SDIO_DCTRL_DTMODE (1 << 2)
|
||||
#define SDIO_DCTRL_DTDIR (1 << 1)
|
||||
#define SDIO_DCTRL_DTEN (1 << 0)
|
||||
#define SDIO_STA_CEATAEND (1 << 23)
|
||||
#define SDIO_STA_SDIOIT (1 << 22)
|
||||
#define SDIO_STA_RXDAVL (1 << 21)
|
||||
#define SDIO_STA_TXDAVL (1 << 20)
|
||||
#define SDIO_STA_RXFIFOE (1 << 19)
|
||||
#define SDIO_STA_TXFIFOE (1 << 18)
|
||||
#define SDIO_STA_RXFIFOF (1 << 17)
|
||||
#define SDIO_STA_TXFIFOF (1 << 16)
|
||||
#define SDIO_STA_RXFIFOHF (1 << 15)
|
||||
#define SDIO_STA_TXFIFOHE (1 << 14)
|
||||
#define SDIO_STA_RXACT (1 << 13)
|
||||
#define SDIO_STA_TXACT (1 << 12)
|
||||
#define SDIO_STA_CMDACT (1 << 11)
|
||||
#define SDIO_STA_DBCKEND (1 << 10)
|
||||
#define SDIO_STA_STBITERR (1 << 9)
|
||||
#define SDIO_STA_DATAEND (1 << 8)
|
||||
#define SDIO_STA_CMDSENT (1 << 7)
|
||||
#define SDIO_STA_CMDREND (1 << 6)
|
||||
#define SDIO_STA_RXOVERR (1 << 5)
|
||||
#define SDIO_STA_TXUNDERR (1 << 4)
|
||||
#define SDIO_STA_DTIMEOUT (1 << 3)
|
||||
#define SDIO_STA_CTIMEOUT (1 << 2)
|
||||
#define SDIO_STA_DCRCFAIL (1 << 1)
|
||||
#define SDIO_STA_CCRCFAIL (1 << 0)
|
||||
#define SDIO_ICR_CEATAENDC (1 << 23)
|
||||
#define SDIO_ICR_SDIOITC (1 << 22)
|
||||
#define SDIO_ICR_DBCKENDC (1 << 10)
|
||||
#define SDIO_ICR_STBITERRC (1 << 9)
|
||||
#define SDIO_ICR_DATAENDC (1 << 8)
|
||||
#define SDIO_ICR_CMDSENTC (1 << 7)
|
||||
#define SDIO_ICR_CMDRENDC (1 << 6)
|
||||
#define SDIO_ICR_RXOVERRC (1 << 5)
|
||||
#define SDIO_ICR_TXUNDERRC (1 << 4)
|
||||
#define SDIO_ICR_DTIMEOUTC (1 << 3)
|
||||
#define SDIO_ICR_CTIMEOUTC (1 << 2)
|
||||
#define SDIO_ICR_DCRCFAILC (1 << 1)
|
||||
#define SDIO_ICR_CCRCFAILC (1 << 0)
|
||||
#define SDIO_MASK_CEATAENDIE (1 << 23)
|
||||
#define SDIO_MASK_SDIOITIE (1 << 22)
|
||||
#define SDIO_MASK_RXDAVLIE (1 << 21)
|
||||
#define SDIO_MASK_TXDAVLIE (1 << 20)
|
||||
#define SDIO_MASK_RXFIFOEIE (1 << 19)
|
||||
#define SDIO_MASK_TXFIFOEIE (1 << 18)
|
||||
#define SDIO_MASK_RXFIFOFIE (1 << 17)
|
||||
#define SDIO_MASK_TXFIFOFIE (1 << 16)
|
||||
#define SDIO_MASK_RXFIFOHFIE (1 << 15)
|
||||
#define SDIO_MASK_TXFIFOHEIE (1 << 14)
|
||||
#define SDIO_MASK_RXACTIE (1 << 13)
|
||||
#define SDIO_MASK_TXACTIE (1 << 12)
|
||||
#define SDIO_MASK_CMDACTIE (1 << 11)
|
||||
#define SDIO_MASK_DBCKENDIE (1 << 10)
|
||||
#define SDIO_MASK_STBITERRIE (1 << 9)
|
||||
#define SDIO_MASK_DATAENDIE (1 << 8)
|
||||
#define SDIO_MASK_CMDSENTIE (1 << 7)
|
||||
#define SDIO_MASK_CMDRENDIE (1 << 6)
|
||||
#define SDIO_MASK_RXOVERRIE (1 << 5)
|
||||
#define SDIO_MASK_TXUNDERRIE (1 << 4)
|
||||
#define SDIO_MASK_DTIMEOUTIE (1 << 3)
|
||||
#define SDIO_MASK_CTIMEOUTIE (1 << 2)
|
||||
#define SDIO_MASK_DCRCFAILIE (1 << 1)
|
||||
#define SDIO_MASK_CCRCFAILIE (1 << 0)
|
||||
|
||||
|
||||
#endif
|
42
systick.c
Normal file
42
systick.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include "system.h"
|
||||
#include "systick.h"
|
||||
#include <stdint.h>
|
||||
/*** SYSTICK ***/
|
||||
|
||||
#define SYSTICK_BASE (0xE000E010)
|
||||
#define SYSTICK_CSR (*(volatile uint32_t *)(SYSTICK_BASE + 0x00))
|
||||
#define SYSTICK_RVR (*(volatile uint32_t *)(SYSTICK_BASE + 0x04))
|
||||
#define SYSTICK_CVR (*(volatile uint32_t *)(SYSTICK_BASE + 0x08))
|
||||
#define SYSTICK_CALIB (*(volatile uint32_t *)(SYSTICK_BASE + 0x0C))
|
||||
|
||||
volatile unsigned int jiffies = 0;
|
||||
|
||||
|
||||
void systick_enable(void)
|
||||
{
|
||||
SYSTICK_RVR = ((cpu_freq / 1000) - 1);
|
||||
SYSTICK_CVR = 0;
|
||||
SYSTICK_CSR |= 0x07;
|
||||
}
|
||||
|
||||
void systick_disable(void)
|
||||
{
|
||||
SYSTICK_CSR &= ~1;
|
||||
}
|
||||
|
||||
void isr_systick(void)
|
||||
{
|
||||
++jiffies;
|
||||
}
|
||||
|
||||
uint32_t HAL_GetTick(void)
|
||||
{
|
||||
return jiffies;
|
||||
}
|
5
systick.h
Normal file
5
systick.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#ifndef SYSTICK_H_INCLUDED
|
||||
#define SYSTICK_H_INCLUDED
|
||||
extern volatile unsigned int jiffies;
|
||||
void systick_enable(void);
|
||||
#endif
|
49
target.ld
Normal file
49
target.ld
Normal file
|
@ -0,0 +1,49 @@
|
|||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
|
||||
RAM (rw) : ORIGIN = 0x20001000, LENGTH = 60K
|
||||
RAM_S (rw) : ORIGIN = 0x20000000, LENGTH = 4K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
_start_text = .;
|
||||
KEEP(*(.isr_vector))
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
_end_text = .;
|
||||
} > FLASH
|
||||
|
||||
.edidx :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.ARM.exidx*)
|
||||
} > FLASH
|
||||
|
||||
_stored_data = .;
|
||||
|
||||
.data : AT (_stored_data)
|
||||
{
|
||||
_start_data = .;
|
||||
*(.data*)
|
||||
. = ALIGN(4);
|
||||
_end_data = .;
|
||||
} > RAM
|
||||
|
||||
.bss :
|
||||
{
|
||||
_start_bss = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_end_bss = .;
|
||||
_end = .;
|
||||
} > RAM
|
||||
|
||||
}
|
||||
|
||||
PROVIDE(_start_heap = _end);
|
||||
PROVIDE(_end_stack = ORIGIN(RAM_S) + LENGTH(RAM_S));
|
118
uart.c
Normal file
118
uart.c
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "uart.h"
|
||||
#include "system.h"
|
||||
|
||||
#define UART2 (0x40004400)
|
||||
|
||||
#define UART2_SR (*(volatile uint32_t *)(UART2))
|
||||
#define UART2_DR (*(volatile uint32_t *)(UART2 + 0x04))
|
||||
#define UART2_BRR (*(volatile uint32_t *)(UART2 + 0x08))
|
||||
#define UART2_CR1 (*(volatile uint32_t *)(UART2 + 0x0c))
|
||||
#define UART2_CR2 (*(volatile uint32_t *)(UART2 + 0x10))
|
||||
|
||||
#define UART_CR1_UART_ENABLE (1 << 13)
|
||||
#define UART_CR1_SYMBOL_LEN (1 << 12)
|
||||
#define UART_CR1_PARITY_ENABLED (1 << 10)
|
||||
#define UART_CR1_PARITY_ODD (1 << 9)
|
||||
#define UART_CR1_TX_ENABLE (1 << 3)
|
||||
#define UART_CR1_RX_ENABLE (1 << 2)
|
||||
#define UART_CR2_STOPBITS (3 << 12)
|
||||
#define UART_SR_TX_EMPTY (1 << 7)
|
||||
#define UART_SR_RX_NOTEMPTY (1 << 5)
|
||||
|
||||
|
||||
|
||||
#define APB1_CLOCK_ER (*(volatile uint32_t *)(0x40023840))
|
||||
#define UART2_APB1_CLOCK_ER_VAL (1 << 17)
|
||||
|
||||
#define AHB1_CLOCK_ER (*(volatile uint32_t *)(0x40023830))
|
||||
#define GPIO_MODE_AF (2)
|
||||
#define UART2_PIN_AF 7
|
||||
#define UART2_RX_PIN 2
|
||||
#define UART2_TX_PIN 3
|
||||
|
||||
static void uart2_pins_setup(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER;
|
||||
/* Set mode = AF */
|
||||
reg = GPIOA_MODE & ~ (0x03 << (UART2_RX_PIN * 2));
|
||||
GPIOA_MODE = reg | (2 << (UART2_RX_PIN * 2));
|
||||
reg = GPIOA_MODE & ~ (0x03 << (UART2_TX_PIN * 2));
|
||||
GPIOA_MODE = reg | (2 << (UART2_TX_PIN * 2));
|
||||
|
||||
/* Alternate function: use low pins */
|
||||
reg = GPIOA_AFL & ~(0xf << ((UART2_TX_PIN) * 4));
|
||||
GPIOA_AFL = reg | (UART2_PIN_AF << ((UART2_TX_PIN) * 4));
|
||||
reg = GPIOA_AFL & ~(0xf << ((UART2_RX_PIN) * 4));
|
||||
GPIOA_AFL = reg | (UART2_PIN_AF << ((UART2_RX_PIN) * 4));
|
||||
}
|
||||
|
||||
int uart2_setup(uint32_t bitrate, uint8_t data, char parity, uint8_t stop)
|
||||
{
|
||||
uint32_t reg;
|
||||
int pin_rx, pin_tx, pin_af;
|
||||
/* Enable pins and configure for AF7 */
|
||||
uart2_pins_setup();
|
||||
/* Turn on the device */
|
||||
APB1_CLOCK_ER |= UART2_APB1_CLOCK_ER_VAL;
|
||||
|
||||
/* Configure for TX */
|
||||
UART2_CR1 |= UART_CR1_TX_ENABLE;
|
||||
|
||||
/* Configure clock */
|
||||
UART2_BRR = cpu_freq / bitrate;
|
||||
|
||||
/* Configure data bits */
|
||||
if (data == 8)
|
||||
UART2_CR1 &= ~UART_CR1_SYMBOL_LEN;
|
||||
else
|
||||
UART2_CR1 |= UART_CR1_SYMBOL_LEN;
|
||||
|
||||
/* Configure parity */
|
||||
switch (parity) {
|
||||
case 'O':
|
||||
UART2_CR1 |= UART_CR1_PARITY_ODD;
|
||||
/* fall through to enable parity */
|
||||
case 'E':
|
||||
UART2_CR1 |= UART_CR1_PARITY_ENABLED;
|
||||
break;
|
||||
default:
|
||||
UART2_CR1 &= ~(UART_CR1_PARITY_ENABLED | UART_CR1_PARITY_ODD);
|
||||
}
|
||||
/* Set stop bits */
|
||||
reg = UART2_CR2 & ~UART_CR2_STOPBITS;
|
||||
if (stop > 1)
|
||||
UART2_CR2 = reg & (2 << 12);
|
||||
else
|
||||
UART2_CR2 = reg;
|
||||
|
||||
/* Turn on uart */
|
||||
UART2_CR1 |= UART_CR1_UART_ENABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _write(void *r, uint8_t *text, int len)
|
||||
{
|
||||
char *p = (char *)text;
|
||||
int i;
|
||||
volatile uint32_t reg;
|
||||
text[len - 1] = 0;
|
||||
while(*p) {
|
||||
do {
|
||||
reg = UART2_SR;
|
||||
} while ((reg & UART_SR_TX_EMPTY) == 0);
|
||||
UART2_DR = *p;
|
||||
p++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
9
uart.h
Normal file
9
uart.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef UART_H_INCLUDED
|
||||
#define UART_H_INCLUDED
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
int uart2_setup(uint32_t bitrate, uint8_t data, char parity, uint8_t stop);
|
||||
void uart2_write(const char *text);
|
||||
|
||||
#endif
|
206
ui.c
Normal file
206
ui.c
Normal file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "system.h"
|
||||
#include "display.h"
|
||||
#include "systick.h"
|
||||
#include "button.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "usecfs.h"
|
||||
|
||||
static const char welcome_message0[]= " There is no ";
|
||||
static const char welcome_message1[]= "knowledge that ";
|
||||
static const char welcome_message2[]= " is not power. ";
|
||||
|
||||
static const uint8_t uuid[UUID_LEN] = {
|
||||
0xb4, 0x6b, 0x82, 0x05, 0xb6, 0xcd, 0x28, 0xaa, 0xc7, 0x81, 0x2e, 0x2d,
|
||||
0xfd, 0xdd, 0x5e, 0x70, 0x3f, 0xbf, 0x09, 0x03, 0x1b, 0x5f, 0xbe, 0xc6,
|
||||
0x09, 0x62, 0xa8, 0x23, 0xe9, 0x99, 0x5e, 0xcb, 0xb4, 0xab, 0x28, 0xdc,
|
||||
0x14, 0xcb, 0x35, 0xb4, 0x7d, 0xfe, 0x26, 0x81, 0x33, 0xd0, 0x4b, 0xc2,
|
||||
0x49, 0x53, 0x05, 0xc3, 0xe7, 0xbd, 0x9a, 0x50, 0xb8, 0x01, 0x30, 0x0b,
|
||||
0x62, 0x58, 0xad, 0xba
|
||||
};
|
||||
|
||||
|
||||
static uint32_t last_action = 0;
|
||||
static uint32_t offset = 0;
|
||||
|
||||
#define ST_LOCKED 0
|
||||
#define ST_PIN_ENTRY 1
|
||||
#define ST_UNLOCKED 2
|
||||
#define MAX_PASSWORD 32
|
||||
|
||||
static int fsm_state = ST_LOCKED;
|
||||
|
||||
static char password[MAX_PASSWORD] = {};
|
||||
static int pin_idx = 0;
|
||||
|
||||
|
||||
#define SLEEP_TIME (5000)
|
||||
|
||||
void ui_msg(const char *txt)
|
||||
{
|
||||
display_scroll(NULL, 0);
|
||||
display_clear(NULL);
|
||||
display_text(6, txt);
|
||||
last_action = jiffies;
|
||||
}
|
||||
|
||||
void lock(void)
|
||||
{
|
||||
//led_on(RED_LED);
|
||||
ui_msg("Locked.");
|
||||
fsm_state = ST_LOCKED;
|
||||
}
|
||||
|
||||
int unlock(void)
|
||||
{
|
||||
uint8_t stored_uuid[UUID_LEN];
|
||||
if (pin_idx < 6) {
|
||||
ui_msg("pin code too short");
|
||||
return -1;
|
||||
}
|
||||
display_scroll(NULL, 0);
|
||||
display_clear(NULL);
|
||||
display_text(6, " ");
|
||||
display_text(5, "Unlocking secret");
|
||||
if ((usecfs_init(password, 0, stored_uuid) == 0) &&
|
||||
(memcmp(stored_uuid, uuid, UUID_LEN) == 0)) {
|
||||
memset(password, 0, MAX_PASSWORD);
|
||||
fsm_state = ST_UNLOCKED;
|
||||
ui_msg("Device UNLOCKED");
|
||||
return 0;
|
||||
} else {
|
||||
#ifdef DEVICE_INITIALIZATION
|
||||
if (usecfs_init(password, 1, uuid) == 0) {
|
||||
display_text(6, "DEVICE INITIALIZED.");
|
||||
fsm_state = ST_UNLOCKED;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
display_text(6, "Failed.");
|
||||
memset(password, 0, MAX_PASSWORD);
|
||||
pin_idx = 0;
|
||||
fsm_state = ST_LOCKED;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ui_button_hold(uint16_t button)
|
||||
{
|
||||
last_action = jiffies;
|
||||
}
|
||||
|
||||
void ui_sdcard_insert(void)
|
||||
{
|
||||
ui_msg("SD Card detected");
|
||||
last_action = jiffies;
|
||||
}
|
||||
|
||||
void ui_menu(char in)
|
||||
{
|
||||
static uint8_t menu_scroll = 0;
|
||||
if (menu_scroll == 0) {
|
||||
display_scroll(NULL, 0);
|
||||
display_clear(NULL);
|
||||
}
|
||||
display_text(7, "1. Status ");
|
||||
display_text(6, "0. Lockdown ");
|
||||
display_text(5, "Main Menu ");
|
||||
display_text(2, "4. Reboot ");
|
||||
display_text(1, "3. SD format ");
|
||||
display_text(0, "2. USB vault ON ");
|
||||
switch (in) {
|
||||
case ' ':
|
||||
menu_scroll += 4;
|
||||
break;
|
||||
case '\r':
|
||||
menu_scroll -= 4;
|
||||
break;
|
||||
}
|
||||
menu_scroll %= 0x40;
|
||||
display_scroll(NULL, menu_scroll);
|
||||
}
|
||||
|
||||
void ui_button_press(uint16_t button)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
if (fsm_state == ST_LOCKED) {
|
||||
ui_msg("Insert pin:");
|
||||
pin_idx = 0;
|
||||
memset(password, 0, MAX_PASSWORD);
|
||||
fsm_state = ST_PIN_ENTRY;
|
||||
return;
|
||||
}
|
||||
if (fsm_state == ST_PIN_ENTRY) {
|
||||
char line[17] = " ";
|
||||
for (i = 0; i < pin_idx; i++) {
|
||||
line[i] = '*';
|
||||
}
|
||||
c = bu2c(button);
|
||||
if ((c >= '0') && (c <='9')) {
|
||||
if (pin_idx < 16) {
|
||||
line[pin_idx] = 'X';
|
||||
}
|
||||
password[pin_idx++] = bu2c(button);
|
||||
}
|
||||
if (c == '\r') {
|
||||
unlock();
|
||||
} else {
|
||||
display_scroll(NULL, 0);
|
||||
display_clear(NULL);
|
||||
display_text(7, line);
|
||||
display_text(6, "Insert pin:");
|
||||
}
|
||||
}
|
||||
if (fsm_state == ST_UNLOCKED)
|
||||
{
|
||||
ui_menu(bu2c(button));
|
||||
}
|
||||
last_action = jiffies;
|
||||
}
|
||||
|
||||
void ui_init(void)
|
||||
{
|
||||
uint32_t now;
|
||||
int i;
|
||||
display_scroll(NULL, 0x3f);
|
||||
display_text(0, welcome_message0);
|
||||
display_text(1, welcome_message1);
|
||||
display_text(2, welcome_message2);
|
||||
now = jiffies;
|
||||
for (i = 0x3f; i >= 0x20; i--) {
|
||||
display_scroll(NULL, i);
|
||||
while ((jiffies - now) < 50)
|
||||
WFI();
|
||||
now = jiffies;
|
||||
}
|
||||
for (i = display_getcontrast(NULL); i >= 0; i--) {
|
||||
display_setcontrast(NULL, i);
|
||||
while ((jiffies - now) < 10)
|
||||
WFI();
|
||||
now = jiffies;
|
||||
}
|
||||
display_scroll(NULL, 0);
|
||||
display_clear(NULL);
|
||||
display_setcontrast(NULL, 0xcf);
|
||||
lock();
|
||||
}
|
||||
|
||||
void ui_keepalive(uint32_t timeslice)
|
||||
{
|
||||
if ((jiffies - last_action) > SLEEP_TIME) {
|
||||
display_scroll(NULL, 0);
|
||||
display_clear(NULL);
|
||||
if (fsm_state == ST_PIN_ENTRY)
|
||||
lock();
|
||||
}
|
||||
}
|
6
ui.h
Normal file
6
ui.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef UI_H
|
||||
#define UI_H
|
||||
|
||||
void ui_init(void);
|
||||
|
||||
#endif
|
54
user_settings.h
Normal file
54
user_settings.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* user_settings.h
|
||||
*/
|
||||
|
||||
#ifndef H_USER_SETTINGS_
|
||||
#define H_USER_SETTINGS_
|
||||
|
||||
/* System */
|
||||
#define WOLFSSL_GENERAL_ALIGNMENT 4
|
||||
#define SINGLE_THREADED
|
||||
//#define WOLFSSL_SMALL_STACK
|
||||
#define WOLFCRYPT_ONLY
|
||||
#define TFM_TIMING_RESISTANT
|
||||
#define HAVE_CHACHA
|
||||
#define HAVE_SHA256
|
||||
#define HAVE_PBKDF2
|
||||
|
||||
#define CUSTOM_RAND_GENERATE random_uint32
|
||||
#define CUSTOM_RAND_TYPE uint32_t
|
||||
|
||||
|
||||
#define WOLFSSL_SP
|
||||
#define WOLFSSL_SP_SMALL
|
||||
#define WOLFSSL_SP_MATH
|
||||
#define SP_WORD_SIZE 32
|
||||
#define SINGLE_THREADED
|
||||
|
||||
/* Disables - For minimum wolfCrypt build */
|
||||
#define NO_AES
|
||||
#define NO_CMAC
|
||||
#define NO_CODING
|
||||
#define NO_RSA
|
||||
#define NO_BIG_INT
|
||||
#define NO_ASN
|
||||
#define NO_RC4
|
||||
#define NO_SHA
|
||||
#define NO_DH
|
||||
#define NO_DSA
|
||||
#define NO_MD4
|
||||
#define NO_RABBIT
|
||||
#define NO_MD5
|
||||
#define NO_SIG_WRAPPER
|
||||
#define NO_CERT
|
||||
#define NO_SESSION_CACHE
|
||||
#define NO_HC128
|
||||
#define NO_DES3
|
||||
#define NO_WRITEV
|
||||
#define NO_DEV_RANDOM
|
||||
#define NO_FILESYSTEM
|
||||
#define NO_MAIN_DRIVER
|
||||
#define NO_OLD_RNGNAME
|
||||
#define NO_WOLFSSL_DIR
|
||||
#define WOLFSSL_NO_SOCK
|
||||
|
||||
#endif /* !H_USER_SETTINGS_ */
|
Loading…
Reference in a new issue