Initial import
This commit is contained in:
commit
22ff79dcdf
43 changed files with 7123 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
|
||||
image.elf
|
||||
image.map
|
||||
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.git
|
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.
|
46
Makefile
Normal file
46
Makefile
Normal file
|
@ -0,0 +1,46 @@
|
|||
CROSS_COMPILE:=arm-none-eabi-
|
||||
CC:=$(CROSS_COMPILE)gcc
|
||||
LD:=$(CROSS_COMPILE)gcc
|
||||
VERSION?=1
|
||||
|
||||
OBJS:=startup.o main.o system.o mem.o led.o \
|
||||
i2c.o display.o font_twisted.o button.o systick.o newlib.o uart.o ui.o timer.o\
|
||||
mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.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=320 \
|
||||
-ffreestanding -Wno-unused -DBLOCK_SIZE=4096 -I. -Ilib/unicore-mx/include \
|
||||
-ffunction-sections -fdata-sections
|
||||
CFLAGS+=-specs=nano.specs -lc -lg
|
||||
CFLAGS+=$(UMXFLAGS)
|
||||
#CFLAGS+=-O3
|
||||
CFLAGS+=-g -ggdb3
|
||||
|
||||
ASFLAGS:=$(CFLAGS)
|
||||
|
||||
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 $(USECFS)/src/*.o
|
||||
make -C lib/unicore-mx clean
|
||||
|
57
adc.c
Normal file
57
adc.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2019
|
||||
* Author: Daniele Lacamera <root@danielinux.net>
|
||||
* GPL2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "adc.h"
|
||||
#include "system.h"
|
||||
|
||||
|
||||
int adc_init(void)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
/* Enable clock */
|
||||
APB2_CLOCK_ER |= ADC1_APB2_CLOCK_ER_VAL;
|
||||
|
||||
/* Power off */
|
||||
ADC1_CR2 &= ~(ADC_CR2_EN);
|
||||
|
||||
/* Set common clock prescaler */
|
||||
ADC_COM_CCR &= ~(0x03 << 16);
|
||||
|
||||
/* Disable scan mode */
|
||||
ADC1_CR1 &= ~(ADC_CR1_SCAN);
|
||||
|
||||
/* Set one-shot (disable continuous mode) */
|
||||
ADC1_CR2 &= ~(ADC_CR2_CONT);
|
||||
|
||||
/* Set sample time for all channels */
|
||||
val = ADC1_SMPR1;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
val |= ADC_SMPR_SMP_480CYC << (i * 3);
|
||||
ADC1_SMPR1 = val;
|
||||
val = ADC1_SMPR2;
|
||||
for (i = 10; i < 18; i++)
|
||||
val |= ADC_SMPR_SMP_480CYC << ((i-10) * 3);
|
||||
}
|
||||
ADC1_SMPR2 = val;
|
||||
ADC1_CR2 &= ~(ADC_CR2_EN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void adc_pin_val(uint32_t ch, uint16_t *val)
|
||||
{
|
||||
ADC1_SQR3 = ch;
|
||||
ADC1_CR2 |= ADC_CR2_EN;
|
||||
ADC1_CR2 |= ADC_CR2_SWSTART;
|
||||
while (ADC1_CR2 & ADC_CR2_SWSTART);;
|
||||
while ((ADC1_SR & ADC_SR_EOC) == 0);;
|
||||
*val= ADC1_DR;
|
||||
printf("Channel %d val %hu\r\n", ch, *val);
|
||||
ADC1_SQR3 = 0;
|
||||
}
|
||||
|
6
adc.h
Normal file
6
adc.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef ADC_H_INCLUDED
|
||||
#define ADC_H_INCLUDED
|
||||
int adc_init(void);
|
||||
int adc_read(void);
|
||||
void adc_pin_val(uint32_t pin, uint16_t *val);
|
||||
#endif
|
221
button.c
Normal file
221
button.c
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* (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"
|
||||
|
||||
// Uncomment to enable debug
|
||||
//#define BUTTON_DEBUG
|
||||
|
||||
enum button_state {
|
||||
IDLE = 0,
|
||||
PRESSING,
|
||||
PRESSED,
|
||||
HOLD,
|
||||
RELEASING,
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef BUTTON_DEBUG
|
||||
# define DBG printf
|
||||
#else
|
||||
# define DBG(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define BUTTON_DEBOUNCE_TIME 50
|
||||
#define BUTTON_HOLD_TIME 1500
|
||||
|
||||
|
||||
|
||||
static volatile int button_press_pending = 0;
|
||||
#define BUTTON_PLUS '+'
|
||||
#define BUTTON_MINUS '-'
|
||||
|
||||
static void input_run(uint32_t ev, void *arg);
|
||||
static void input_init(void);
|
||||
|
||||
const char button_task_name[] = "Input";
|
||||
|
||||
// PA8 + PA9 // ROTARY encoder
|
||||
// PC0 // BUTTON
|
||||
//
|
||||
// TODO:
|
||||
// C4 + C5 rotary
|
||||
// B0 + B1 + C3 Buttons (- + RotSW)
|
||||
//
|
||||
|
||||
void pin_exti_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void pin_exti_start_read(void)
|
||||
{
|
||||
exti_set_trigger(GPIO0|GPIO1|GPIO3|GPIO4|GPIO5, EXTI_TRIGGER_BOTH);
|
||||
exti_enable_request(GPIO0);
|
||||
exti_enable_request(GPIO1);
|
||||
exti_enable_request(GPIO3);
|
||||
exti_enable_request(GPIO4);
|
||||
exti_enable_request(GPIO5);
|
||||
}
|
||||
|
||||
|
||||
static void button_setup(void)
|
||||
{
|
||||
rcc_periph_clock_enable(RCC_SYSCFG);
|
||||
rcc_periph_clock_enable(RCC_GPIOB);
|
||||
rcc_periph_clock_enable(RCC_GPIOC);
|
||||
gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO3 | GPIO4 | GPIO5);
|
||||
gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO0 | GPIO1);
|
||||
nvic_enable_irq(NVIC_EXTI9_5_IRQ);
|
||||
nvic_enable_irq(NVIC_EXTI0_IRQ);
|
||||
nvic_enable_irq(NVIC_EXTI1_IRQ);
|
||||
nvic_enable_irq(NVIC_EXTI3_IRQ);
|
||||
nvic_enable_irq(NVIC_EXTI4_IRQ);
|
||||
nvic_set_priority(NVIC_EXTI9_5_IRQ, 1);
|
||||
nvic_set_priority(NVIC_EXTI0_IRQ, 1);
|
||||
nvic_set_priority(NVIC_EXTI1_IRQ, 1);
|
||||
nvic_set_priority(NVIC_EXTI3_IRQ, 1);
|
||||
nvic_set_priority(NVIC_EXTI4_IRQ, 1);
|
||||
exti_select_source(GPIO0, GPIOB);
|
||||
exti_select_source(GPIO1, GPIOB);
|
||||
exti_select_source(GPIO3, GPIOC);
|
||||
exti_select_source(GPIO4, GPIOC);
|
||||
exti_select_source(GPIO5, GPIOC);
|
||||
}
|
||||
|
||||
static volatile uint32_t rot_up = 0;
|
||||
static volatile uint32_t rot_down = 0;
|
||||
|
||||
static void button_start_read(void)
|
||||
{
|
||||
exti_set_trigger(GPIO0|GPIO1|GPIO3, EXTI_TRIGGER_RISING);
|
||||
exti_set_trigger(GPIO4, EXTI_TRIGGER_FALLING);
|
||||
exti_enable_request(GPIO0);
|
||||
exti_enable_request(GPIO1);
|
||||
exti_enable_request(GPIO3);
|
||||
exti_enable_request(GPIO4);
|
||||
}
|
||||
|
||||
|
||||
static volatile uint32_t last_rot_ev = 0;
|
||||
void isr_exti_rot0(void)
|
||||
{
|
||||
uint32_t rot_val = gpio_get(GPIOC, GPIO4 | GPIO5);
|
||||
if ((jiffies - last_rot_ev) > 100) {
|
||||
if ((rot_val & GPIO4) == 0) {
|
||||
|
||||
if ((rot_val & GPIO5) == 0)
|
||||
rot_down++;
|
||||
else
|
||||
rot_up++;
|
||||
}
|
||||
}
|
||||
exti_reset_request(GPIO4);
|
||||
exti_reset_request(GPIO5);
|
||||
}
|
||||
|
||||
void isr_exti_button(void)
|
||||
{
|
||||
uint32_t pending;
|
||||
|
||||
pending = (gpio_get(GPIOB, GPIO0|GPIO1));
|
||||
if ((pending & GPIO0) != 0) {
|
||||
button_press_pending = '-';
|
||||
}
|
||||
if ((pending & GPIO1) != 0) {
|
||||
button_press_pending = '+';
|
||||
}
|
||||
if (!pending) {
|
||||
pending = (gpio_get(GPIOC, GPIO3));
|
||||
if ((pending & GPIO3) != 0) {
|
||||
button_press_pending = '*';
|
||||
}
|
||||
}
|
||||
exti_reset_request(GPIO0);
|
||||
exti_reset_request(GPIO1);
|
||||
exti_reset_request(GPIO3);
|
||||
}
|
||||
|
||||
static uint32_t t0s, t0us;
|
||||
static uint32_t t1s, t1us;
|
||||
|
||||
static uint32_t time_diff_ms(uint32_t s_a, uint32_t us_a, uint32_t s_b, uint32_t us_b)
|
||||
{
|
||||
uint32_t res = 0;
|
||||
res = (s_a - s_b) * 1000;
|
||||
if (us_b > us_a) {
|
||||
us_a += 1000000;
|
||||
res -= 1000;
|
||||
}
|
||||
res += (us_a - us_b) / 1000;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* 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))
|
||||
{
|
||||
int b = 0;
|
||||
int st;
|
||||
static uint32_t last_event = 0;
|
||||
static uint32_t pressed_start = 0;
|
||||
while(rot_down > 0) {
|
||||
callback('D',0);
|
||||
rot_down--;
|
||||
}
|
||||
while(rot_up > 0) {
|
||||
callback('U',0);
|
||||
rot_up--;
|
||||
}
|
||||
|
||||
if (jiffies - last_event < BUTTON_DEBOUNCE_TIME)
|
||||
return;
|
||||
last_event = jiffies;
|
||||
st = !!(gpio_get(GPIOB, GPIO0 | GPIO1) | gpio_get(GPIOC, GPIO3));
|
||||
if (!st) {
|
||||
pressed_start = 0;
|
||||
}
|
||||
|
||||
if ((button_press_pending) && st) {
|
||||
if ((pressed_start == 0) || ((jiffies - pressed_start) > BUTTON_HOLD_TIME)) {
|
||||
pressed_start = jiffies;
|
||||
callback(button_press_pending, 0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
button_press_pending = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void button_init(void)
|
||||
{
|
||||
memset(Buttons, 0, sizeof(struct user_button) * N_BUTTONS);
|
||||
button_setup();
|
||||
button_start_read();
|
||||
}
|
||||
|
||||
|
16
button.h
Normal file
16
button.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef BUTTON_H_INCLUDED
|
||||
#define BUTTON_H_INCLUDED
|
||||
#include "unicore-mx/stm32/gpio.h"
|
||||
|
||||
static const uint32_t Channel[5] = { 8, 9, 7, 6, 5 };
|
||||
static const uint32_t Channel_Pin[5] = { GPIO8, GPIO9, GPIO7, GPIO6, GPIO5 };
|
||||
static const char Channel_name[5][16] = { "Red", "Purple", "Green", "Blue", "Yellow" };
|
||||
|
||||
|
||||
void button_init(void);
|
||||
int button_poll(void (*callback)(uint8_t press, int hold));
|
||||
int input_get_swr(void);
|
||||
|
||||
#define N_BUTTONS 2
|
||||
|
||||
#endif
|
174
dac.c
Normal file
174
dac.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* (c) danielinux 2020
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
|
||||
#include <unicore-mx/cm3/nvic.h>
|
||||
#include <unicore-mx/stm32/dma.h>
|
||||
#include <unicore-mx/stm32/dac.h>
|
||||
#include <unicore-mx/stm32/gpio.h>
|
||||
#include <unicore-mx/stm32/rcc.h>
|
||||
#include <unicore-mx/stm32/timer.h>
|
||||
#include "pot.h"
|
||||
|
||||
#define DAC_BUFSIZ 512
|
||||
extern const unsigned char raw_au[];
|
||||
const unsigned int raw_au_len;
|
||||
|
||||
static volatile int dac_written;
|
||||
static int dac_transfer_size;
|
||||
static int dac_chunk_size;
|
||||
static uint8_t dac_outb[DAC_BUFSIZ];
|
||||
|
||||
static void dac_xmit(void)
|
||||
{
|
||||
uint32_t size = DAC_BUFSIZ;
|
||||
if ((dac_transfer_size - dac_written ) < size)
|
||||
size = dac_transfer_size - dac_written;
|
||||
dac_chunk_size = size;
|
||||
|
||||
/* Start DMA transfer of waveform */
|
||||
dac_trigger_enable(CHANNEL_1);
|
||||
dac_set_trigger_source(DAC_CR_TSEL1_T2);
|
||||
dac_dma_enable(CHANNEL_1);
|
||||
dma_set_memory_address(DMA1, DMA_STREAM5, (uint32_t) (dac_outb + dac_written));
|
||||
dma_set_number_of_data(DMA1, DMA_STREAM5, size);
|
||||
dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM5);
|
||||
dma_channel_select(DMA1, DMA_STREAM5, DMA_SxCR_CHSEL_7);
|
||||
dma_enable_stream(DMA1, DMA_STREAM5);
|
||||
}
|
||||
|
||||
int dac_write(const void *buf, unsigned int len)
|
||||
{
|
||||
if (dac_written < dac_transfer_size) {
|
||||
if ((len + dac_transfer_size) > DAC_BUFSIZ)
|
||||
return 0;
|
||||
}
|
||||
if (dac_written >= dac_transfer_size) {
|
||||
dac_written = 0;
|
||||
dac_transfer_size = 0;
|
||||
}
|
||||
memcpy(dac_outb + dac_transfer_size, buf, len);
|
||||
dac_transfer_size += len;
|
||||
dac_xmit();
|
||||
return dac_written;
|
||||
}
|
||||
|
||||
int dac_space(void)
|
||||
{
|
||||
if (dac_written >= dac_transfer_size) {
|
||||
dac_written = 0;
|
||||
dac_transfer_size = 0;
|
||||
}
|
||||
return DAC_BUFSIZ - dac_transfer_size;
|
||||
}
|
||||
|
||||
|
||||
/* IRQ Handler */
|
||||
void dma1_stream5_isr(void)
|
||||
{
|
||||
if (dma_get_interrupt_flag(DMA1, DMA_STREAM5, DMA_TCIF)) {
|
||||
if (dac_written < dac_transfer_size)
|
||||
dac_written += dac_chunk_size;
|
||||
|
||||
dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF);
|
||||
dma_disable_stream(DMA1, DMA_STREAM5);
|
||||
dac_trigger_disable(CHANNEL_1);
|
||||
dac_dma_disable(CHANNEL_1);
|
||||
if (dac_written >= dac_transfer_size) {
|
||||
return;
|
||||
} else {
|
||||
dac_xmit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Initialization functions */
|
||||
|
||||
//#define PERIOD (5200)
|
||||
#define PERIOD 8800
|
||||
static void timer_setup(void)
|
||||
{
|
||||
/* Enable TIM2 clock. */
|
||||
rcc_periph_clock_enable(RCC_TIM2);
|
||||
timer_reset(TIM2);
|
||||
/* Timer global mode: - No divider, Alignment edge, Direction up */
|
||||
timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT,
|
||||
TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
|
||||
timer_continuous_mode(TIM2);
|
||||
timer_set_period(TIM2, PERIOD);
|
||||
timer_disable_oc_output(TIM2, TIM_OC2 | TIM_OC3 | TIM_OC4);
|
||||
timer_enable_oc_output(TIM2, TIM_OC1);
|
||||
timer_disable_oc_clear(TIM2, TIM_OC1);
|
||||
timer_disable_oc_preload(TIM2, TIM_OC1);
|
||||
timer_set_oc_slow_mode(TIM2, TIM_OC1);
|
||||
timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_TOGGLE);
|
||||
timer_set_oc_value(TIM2, TIM_OC1, 500);
|
||||
timer_disable_preload(TIM2);
|
||||
/* Set the timer trigger output (for the DAC) to the channel 1 output
|
||||
* compare */
|
||||
timer_set_master_mode(TIM2, TIM_CR2_MMS_COMPARE_OC1REF);
|
||||
timer_enable_counter(TIM2);
|
||||
}
|
||||
|
||||
|
||||
static void dac_dma_setup(void)
|
||||
{
|
||||
/* DAC channel 1 uses DMA controller 1 Stream 5 Channel 7. */
|
||||
/* Enable DMA1 clock and IRQ */
|
||||
rcc_periph_clock_enable(RCC_DMA1);
|
||||
nvic_set_priority(NVIC_DMA1_STREAM5_IRQ, 1);
|
||||
nvic_enable_irq(NVIC_DMA1_STREAM5_IRQ);
|
||||
dma_stream_reset(DMA1, DMA_STREAM5);
|
||||
dma_set_priority(DMA1, DMA_STREAM5, DMA_SxCR_PL_LOW);
|
||||
dma_set_memory_size(DMA1, DMA_STREAM5, DMA_SxCR_MSIZE_8BIT);
|
||||
dma_set_peripheral_size(DMA1, DMA_STREAM5, DMA_SxCR_PSIZE_8BIT);
|
||||
dma_enable_memory_increment_mode(DMA1, DMA_STREAM5);
|
||||
dma_enable_circular_mode(DMA1, DMA_STREAM5);
|
||||
dma_set_transfer_mode(DMA1, DMA_STREAM5,
|
||||
DMA_SxCR_DIR_MEM_TO_PERIPHERAL);
|
||||
/* The register to target is the DAC1 8-bit right justified data
|
||||
register */
|
||||
dma_set_peripheral_address(DMA1, DMA_STREAM5, (uint32_t) &DAC_DHR8R1);
|
||||
}
|
||||
|
||||
static void dac_hw_init(data_channel c)
|
||||
{
|
||||
/* Set DAC GPIO pin to analog mode */
|
||||
rcc_periph_clock_enable(RCC_GPIOC);
|
||||
gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4);
|
||||
timer_setup();
|
||||
|
||||
/* Set up DAC */
|
||||
rcc_periph_clock_enable(RCC_DAC);
|
||||
dac_enable(c);
|
||||
}
|
||||
|
||||
void dac_play(const uint8_t *buf, int len)
|
||||
{
|
||||
int i = 0;
|
||||
int space;
|
||||
while(i < len) {
|
||||
space = dac_space();
|
||||
if (space > 0) {
|
||||
if (space > (len - i))
|
||||
space = len - i;
|
||||
dac_write(buf + i, space);
|
||||
i += space;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int dac_init(void)
|
||||
{
|
||||
int i;
|
||||
dac_hw_init(CHANNEL_1);
|
||||
dac_dma_setup();
|
||||
pot_set_master(200);
|
||||
dac_play(raw_au, raw_au_len);
|
||||
return 0;
|
||||
}
|
15
dac.h
Normal file
15
dac.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
|
||||
#ifndef DAC_H_INCLUDED
|
||||
#define DAC_H_INCLUDED
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
void dac_init(void);
|
||||
int dac_write(const void *buf, unsigned int len);
|
||||
int dac_play(const void *buf, unsigned int len);
|
||||
|
||||
#define pot_get_master() pot_get(2)
|
||||
#define pot_set_master(x) pot_set(2,x)
|
||||
|
||||
#endif
|
137
display.c
Normal file
137
display.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* (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, 0x00);
|
||||
display_send_cmd2(NULL, SSD1306_COLUMNADDR, 0, WIDTH - 1);
|
||||
for (j = 0; j < 16; j++)
|
||||
display_send_data(NULL, zeros, 8);
|
||||
}
|
||||
WFI();
|
||||
WFI();
|
||||
WFI();
|
||||
}
|
||||
|
||||
void display_text(int row, const char *text)
|
||||
{
|
||||
int k;
|
||||
uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
int len = strlen(text);
|
||||
if (len > 15)
|
||||
len = 15;
|
||||
|
||||
display_send_cmd(NULL, 0x00);
|
||||
display_send_cmd(NULL, 0x10);
|
||||
WFI();
|
||||
display_send_cmd2(NULL, SSD1306_PAGEADDR, 7 - row, 0x00);
|
||||
display_send_cmd2(NULL, SSD1306_COLUMNADDR, 0, WIDTH - 1);
|
||||
for(k = 0; k < len; k++)
|
||||
display_send_data(NULL, fb_font[text[k]], 8);
|
||||
for(; k < 16; k++)
|
||||
display_send_data(NULL, zeros, 8);
|
||||
}
|
||||
|
||||
void display_text_inverse(int row, const char *text)
|
||||
{
|
||||
int k, j;
|
||||
uint8_t inv_buf[8];
|
||||
uint8_t ones[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
int len = strlen(text);
|
||||
if (len > 15)
|
||||
len = 15;
|
||||
display_send_cmd(NULL, 0x00);
|
||||
display_send_cmd(NULL, 0x10);
|
||||
WFI();
|
||||
display_send_cmd2(NULL, SSD1306_PAGEADDR, 7 - row, 0x00);
|
||||
display_send_cmd2(NULL, SSD1306_COLUMNADDR, 0, WIDTH - 1);
|
||||
for(k = 0; k < len; k++) {
|
||||
for (j = 0; j < 8; j++)
|
||||
inv_buf[j] = ~fb_font[text[k]][j];
|
||||
display_send_data(NULL, inv_buf, 8);
|
||||
}
|
||||
for(; k < 16; k++)
|
||||
display_send_data(NULL, ones, 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;
|
||||
}
|
56
display.h
Normal file
56
display.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#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_text_inverse(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.
313
i2c.c
Normal file
313
i2c.c
Normal file
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
* (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 DJHERO_I2C_ADDR 0x52
|
||||
//#define DJHERO_I2C_ADDR 0x29
|
||||
|
||||
|
||||
#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));
|
||||
|
||||
/* Set pull-up */
|
||||
#if 0
|
||||
reg = GPIOB_PUPD & (0x03 << (I2C1_SCL * 2));
|
||||
GPIOB_PUPD = reg | (0x01 << (I2C1_SCL * 2));
|
||||
reg = GPIOB_PUPD & (0x03 << (I2C1_SDA * 2));
|
||||
GPIOB_PUPD = reg | (0x01 << (I2C1_SDA * 2));
|
||||
#endif
|
||||
|
||||
/* 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_sendrecv(uint8_t address, const uint8_t *wbuf, int wlen, uint8_t *rbuf, int rlen)
|
||||
{
|
||||
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 < wlen; i++) {
|
||||
I2C1_DR = wbuf[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);
|
||||
}
|
||||
for (i = 0; i < rlen; i++) {
|
||||
I2C1_DR = 0xFF;
|
||||
do {
|
||||
sr1 = I2C1_SR1;
|
||||
if ((sr1 & I2C_SR1_RX_NOTEMPTY) == I2C_SR1_RX_NOTEMPTY) {
|
||||
rbuf[i] = I2C1_DR;
|
||||
}
|
||||
} while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0);
|
||||
}
|
||||
while ((sr1 & (I2C_SR1_TX_BTF)) == 0) {
|
||||
sr1 = I2C1_SR1;
|
||||
}
|
||||
i2c1_send_stop();
|
||||
return i;
|
||||
}
|
||||
|
||||
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); /* 400 Khz */
|
||||
// I2C1_CCR = reg | (APB1_SPEED_IN_MHZ * 20); /* 100 Khz */
|
||||
// I2C1_CCR = reg | (APB1_SPEED_IN_MHZ * 40); /* 50 Khz */
|
||||
|
||||
reg = I2C1_TRISE & ~(I2C_TRISE_MASK);
|
||||
I2C1_TRISE = reg | (APB1_SPEED_IN_MHZ + 1);
|
||||
|
||||
I2C1_CR1 |= I2C_CR1_ENABLE;
|
||||
}
|
||||
|
||||
void i2c_display_init(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void djhero_init(void)
|
||||
{
|
||||
const uint8_t cmd1[2] = { 0xf0, 0x55 };
|
||||
const uint8_t cmd2[2] = { 0xfb, 0x00 };
|
||||
const uint8_t cmdquery[1] = { 0xFA };
|
||||
uint8_t serial[6];
|
||||
|
||||
i2c1_send(DJHERO_I2C_ADDR, cmd1, 2);
|
||||
i2c1_send(DJHERO_I2C_ADDR, cmd2, 2);
|
||||
i2c1_sendrecv(DJHERO_I2C_ADDR, cmdquery, 1, serial, 6);
|
||||
|
||||
}
|
||||
|
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
|
92
led.c
Normal file
92
led.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "unicore-mx/stm32/gpio.h"
|
||||
#include "unicore-mx/stm32/rcc.h"
|
||||
#include "system.h"
|
||||
#include "led.h"
|
||||
#include "pinout.h"
|
||||
|
||||
|
||||
/* LEDS mapping:
|
||||
*
|
||||
* E0 - Heartbeat
|
||||
* E10 - 1
|
||||
* B2 - 2
|
||||
* E8 - 3
|
||||
* E9 - 4
|
||||
* E1 - 5
|
||||
* E7 - 6
|
||||
* B8 - 7
|
||||
* B9 - 8
|
||||
*/
|
||||
|
||||
#define NUM_LEDS 9
|
||||
|
||||
#define LD0 (1 << 0)
|
||||
#define LD1 (1 << 10)
|
||||
#define LD2 (1 << 2)
|
||||
#define LD3 (1 << 8)
|
||||
#define LD4 (1 << 9)
|
||||
#define LD5 (1 << 1)
|
||||
#define LD6 (1 << 7)
|
||||
#define LD7 (1 << 8)
|
||||
#define LD8 (1 << 9)
|
||||
|
||||
|
||||
#define BANK_B_LD (LD2 | LD7 | LD8)
|
||||
#define BANK_E_LD (LD0 | LD1 | LD3 | LD4 | LD5 | LD6)
|
||||
|
||||
|
||||
struct pin Leds[9] = {
|
||||
{ GPIOE, 1 << 0 },
|
||||
{ GPIOE, 1 << 10 },
|
||||
{ GPIOB, 1 << 2 },
|
||||
{ GPIOE, 1 << 8 },
|
||||
{ GPIOE, 1 << 9 },
|
||||
{ GPIOE, 1 << 1 },
|
||||
{ GPIOB, 1 << 8 },
|
||||
{ GPIOB, 1 << 9 },
|
||||
};
|
||||
|
||||
void led_setup(void)
|
||||
{
|
||||
rcc_periph_clock_enable(RCC_GPIOB);
|
||||
rcc_periph_clock_enable(RCC_GPIOE);
|
||||
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, BANK_B_LD);
|
||||
gpio_set(GPIOB, BANK_B_LD);
|
||||
gpio_mode_setup(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, BANK_E_LD);
|
||||
gpio_set(GPIOE, BANK_E_LD);
|
||||
}
|
||||
|
||||
void led_on(int led)
|
||||
{
|
||||
gpio_set(Leds[led].bank, Leds[led].pin);
|
||||
}
|
||||
|
||||
void led_off(int led)
|
||||
{
|
||||
gpio_clear(Leds[led].bank, Leds[led].pin);
|
||||
}
|
||||
|
||||
void led_toggle(int led)
|
||||
{
|
||||
if (gpio_get(Leds[led].bank, Leds[led].pin))
|
||||
gpio_clear(Leds[led].bank, Leds[led].pin);
|
||||
else
|
||||
gpio_set(Leds[led].bank, Leds[led].pin);
|
||||
}
|
||||
|
||||
void led_beat(int b)
|
||||
{
|
||||
if (b < 1 || b > 8)
|
||||
return;
|
||||
gpio_clear(GPIOB, BANK_B_LD);
|
||||
gpio_clear(GPIOE, BANK_E_LD);
|
||||
led_on(b);
|
||||
}
|
||||
|
13
led.h
Normal file
13
led.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef LED_H
|
||||
#define LED_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "system.h"
|
||||
|
||||
void led_setup(void);
|
||||
void led_on(int led);
|
||||
void led_off(int led);
|
||||
void led_toggle(int led);
|
||||
void led_beat(int b);
|
||||
|
||||
#endif
|
1
lib/unicore-mx
Submodule
1
lib/unicore-mx
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 72be4686cba2d190765695477e735ca10ca473cf
|
153
main.c
Normal file
153
main.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "system.h"
|
||||
#include "led.h"
|
||||
#include "display.h"
|
||||
#include "spi_flash.h"
|
||||
#include "uart.h"
|
||||
#include "systick.h"
|
||||
#include "ui.h"
|
||||
#include "button.h"
|
||||
#include "adc.h"
|
||||
extern uint32_t cpu_freq;
|
||||
|
||||
#define BLINK_INTERVAL 500
|
||||
|
||||
static int sdcard_detected = 0;
|
||||
|
||||
|
||||
static void bootlevel_0(void)
|
||||
{
|
||||
clock_pll_on();
|
||||
uart2_setup(115200, 8, 0, 1);
|
||||
systick_enable();
|
||||
WFI();
|
||||
printf("Console on USART2 Enabled.\r\n");
|
||||
printf("\r\n=====================\r\n");
|
||||
printf("Entering bootlevel 0.\r\n");
|
||||
led_setup();
|
||||
led_on(0);
|
||||
printf("System clock started.\r\n");
|
||||
button_init();
|
||||
//pin_exti_init();
|
||||
printf("Buttons initialized.\r\n");
|
||||
}
|
||||
|
||||
extern void timer_init(void);
|
||||
|
||||
static void bootlevel_1(void)
|
||||
{
|
||||
uint16_t spiflash_vendor;
|
||||
int sdcard_present;
|
||||
printf("=====================\r\n");
|
||||
printf("Entering bootlevel 1.\r\n");
|
||||
|
||||
printf("Initializing ADC...\r\n");
|
||||
adc_init();
|
||||
|
||||
printf("Initializing digital-potmeters\r\n");
|
||||
pot_init();
|
||||
|
||||
printf("Initializing DAC...\r\n");
|
||||
dac_init();
|
||||
|
||||
printf("Activating I2C bus...\r\n");
|
||||
i2c1_setup();
|
||||
i2c_display_init();
|
||||
printf("Display initialized.\r\n");
|
||||
printf("Displaying splash screen...\r\n");
|
||||
ui_init();
|
||||
printf("UI initialized.\r\n");
|
||||
//djhero_init();
|
||||
timer_init();
|
||||
|
||||
printf("System up and running.\r\n\n\n");
|
||||
}
|
||||
|
||||
static void (*process_input_callback)(uint8_t press, int hold) = NULL;
|
||||
static void (*keepalive_callback)(void) = NULL;
|
||||
|
||||
void set_input_callback(void (*cb)(uint8_t press, int hold))
|
||||
{
|
||||
process_input_callback = cb;
|
||||
}
|
||||
|
||||
void clear_input_callback(void)
|
||||
{
|
||||
process_input_callback = NULL;
|
||||
}
|
||||
|
||||
void set_keepalive(void (*cb)(void))
|
||||
{
|
||||
keepalive_callback = cb;
|
||||
}
|
||||
|
||||
void clear_keepalive(void)
|
||||
{
|
||||
keepalive_callback = NULL;
|
||||
}
|
||||
|
||||
void process_button(uint8_t press, int hold)
|
||||
{
|
||||
static uint32_t last_b_time = 0;
|
||||
if (jiffies - last_b_time < 100)
|
||||
return;
|
||||
last_b_time = jiffies;
|
||||
if (process_input_callback)
|
||||
process_input_callback(press, hold);
|
||||
else
|
||||
ui_button_press(press, hold);
|
||||
}
|
||||
|
||||
extern void gettime(uint32_t *s, uint32_t *us);
|
||||
int main(void) {
|
||||
int hb = 1;
|
||||
int fs_on = 0;
|
||||
int ret;
|
||||
char uc;
|
||||
volatile uint32_t poll_time = 0;
|
||||
uint32_t bstatus = 0;
|
||||
|
||||
const uint32_t hb_len = 20;
|
||||
const uint32_t hb_pulse = 5;
|
||||
|
||||
bootlevel_0();
|
||||
bootlevel_1();
|
||||
//pin_exti_start_read();
|
||||
|
||||
while(1) {
|
||||
hb = 1;
|
||||
led_on(LED);
|
||||
poll_time = jiffies;
|
||||
|
||||
if (!keepalive_callback)
|
||||
ui_keepalive(hb_len);
|
||||
else
|
||||
keepalive_callback();
|
||||
|
||||
|
||||
do {
|
||||
WFI();
|
||||
ret = button_poll(process_button);
|
||||
uc = uart_read();
|
||||
if (uc)
|
||||
process_button(uc, 0);
|
||||
if (jiffies - poll_time > hb_pulse) {
|
||||
if (hb) {
|
||||
uint32_t s, us;
|
||||
hb = 0;
|
||||
led_off(LED);
|
||||
// gettime(&s, &us);
|
||||
// printf("TIME: %u.%05u\r\n", s, us);
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
47
mutex.S
Normal file
47
mutex.S
Normal file
|
@ -0,0 +1,47 @@
|
|||
|
||||
.syntax unified
|
||||
|
||||
/* Lock function.
|
||||
* On success, return 0.
|
||||
* On failure, return -1 (Locked, try again later).
|
||||
*/
|
||||
|
||||
.global _mutex_lock
|
||||
_mutex_lock:
|
||||
LDREX r1, [r0]
|
||||
CMP r1, #0 // Test if mutex holds the value 0
|
||||
BEQ _mutex_lock_fail // If it does, return -1
|
||||
SUBS r1, #1 // If not, decrement temporary copy
|
||||
STREX r2, r1, [r0] // Attempt Store-Exclusive
|
||||
CMP r2, #0 // Check if Store-Exclusive succeeded
|
||||
BNE _mutex_lock // If Store-Exclusive failed, retry from start
|
||||
DMB // Required before accessing protected resource
|
||||
MOVS r0, #0 // Successfully locked.
|
||||
BX lr
|
||||
_mutex_lock_fail:
|
||||
DMB
|
||||
MOV r0, #-1 // Already locked!
|
||||
BX lr
|
||||
|
||||
/* Unlock mutex.
|
||||
* On success, return 0.
|
||||
* On failure, return -1 (Already unlocked!).
|
||||
*/
|
||||
|
||||
.global _mutex_unlock
|
||||
_mutex_unlock:
|
||||
LDREX r1, [r0]
|
||||
CMP r1, #0 // Test if mutex holds the value 0
|
||||
BNE _mutex_unlock_fail // If it does not, it's already unlocked!
|
||||
ADDS r1, #1 // Increment temporary copy
|
||||
STREX r2, r1, [r0] // Attempt Store-Exclusive
|
||||
CMP r2, #0 // Check if Store-Exclusive succeeded
|
||||
BNE _mutex_unlock // Store failed - retry immediately
|
||||
DMB // Required before releasing protected resource
|
||||
MOVS r0, #0 // Successfully unlocked.
|
||||
BX lr
|
||||
_mutex_unlock_fail:
|
||||
DMB
|
||||
MOV r0, #-1 // Already unlocked!
|
||||
BX lr
|
||||
|
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;
|
||||
}
|
||||
|
||||
|
13
pinout.h
Normal file
13
pinout.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef PIN_INCLUDED
|
||||
#define PIN_INCLUDED
|
||||
#include <stdint.h>
|
||||
|
||||
struct pin {
|
||||
uint32_t bank;
|
||||
uint32_t pin;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
129
pot.c
Normal file
129
pot.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
#include <stdint.h>
|
||||
#include "unicore-mx/stm32/gpio.h"
|
||||
#include "unicore-mx/stm32/rcc.h"
|
||||
#include "system.h"
|
||||
#include "led.h"
|
||||
#include "pinout.h"
|
||||
|
||||
extern volatile uint32_t jiffies;
|
||||
|
||||
uint32_t p1_lvl, p0_lvl, master_lvl;
|
||||
|
||||
|
||||
static int pot_cs[3] = { 8, 7, 6 }; // PC6, PC7, PC8
|
||||
|
||||
#define POT0 GPIO8 // C8
|
||||
#define POT1 GPIO7 // C7
|
||||
#define POTM GPIO6 // C6
|
||||
#define POTINC GPIO15 // D15
|
||||
#define POTUD GPIO14 // D14
|
||||
|
||||
#define NUM_POTS 3
|
||||
#define POT_CS_PINS (POT0 | POT1 | POTM)
|
||||
#define POT_CTRL_PINS (POTINC | POTUD)
|
||||
|
||||
|
||||
static uint32_t Pots[NUM_POTS] = { POT0, POT1, POTM };
|
||||
static int Levels[NUM_POTS] = { 0, 0, 0 };
|
||||
|
||||
|
||||
static void p_offset(int p, int offset)
|
||||
{
|
||||
uint32_t cs;
|
||||
int i;
|
||||
int sign = 0;
|
||||
int u_off = offset;
|
||||
volatile uint32_t now;
|
||||
if((p < 0) || (p > NUM_POTS))
|
||||
return;
|
||||
cs = Pots[p];
|
||||
if (offset < 0) {
|
||||
sign = 1;
|
||||
u_off = 0 - offset;
|
||||
}
|
||||
/* U/!D setting */
|
||||
if (sign)
|
||||
gpio_clear(GPIOD, POTUD);
|
||||
else
|
||||
gpio_set(GPIOD, POTUD);
|
||||
|
||||
for (i = 0; i < u_off; i++) {
|
||||
|
||||
/* /CS on */
|
||||
gpio_clear(GPIOC, cs);
|
||||
DMB();
|
||||
/* /INC on */
|
||||
gpio_clear(GPIOD, POTINC);
|
||||
DMB();
|
||||
/* /INC off */
|
||||
gpio_set(GPIOD, POTINC);
|
||||
/* /CS off first (no store) */
|
||||
gpio_set(GPIOC,cs);
|
||||
//WFI();
|
||||
for (int j = 0; j < 4000; j++)
|
||||
;;
|
||||
}
|
||||
|
||||
Levels[p] += offset;
|
||||
if (Levels[p] > 100)
|
||||
Levels[p] = 100;
|
||||
if (Levels[p] < 0)
|
||||
Levels[p] = 0;
|
||||
}
|
||||
|
||||
void pot_offset(int p, int offset)
|
||||
{
|
||||
if ((Levels[p] + offset) > 100) {
|
||||
offset = 100 - Levels[p];
|
||||
}
|
||||
|
||||
if ((Levels[p] + offset) < 0) {
|
||||
offset = 0 - Levels[p];
|
||||
}
|
||||
|
||||
if (offset == 0)
|
||||
return;
|
||||
|
||||
p_offset(p, offset);
|
||||
}
|
||||
|
||||
void pot_init(void)
|
||||
{
|
||||
int i;
|
||||
rcc_periph_clock_enable(RCC_GPIOC);
|
||||
rcc_periph_clock_enable(RCC_GPIOD);
|
||||
|
||||
gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, POT_CS_PINS);
|
||||
gpio_set_output_options(GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_100MHZ, POT_CS_PINS);
|
||||
gpio_set(GPIOC, POT_CS_PINS);
|
||||
|
||||
gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, POT_CTRL_PINS);
|
||||
gpio_set_output_options(GPIOD, GPIO_OTYPE_OD, GPIO_OSPEED_100MHZ, POT_CTRL_PINS);
|
||||
gpio_set(GPIOD, POT_CTRL_PINS);
|
||||
|
||||
for (i = 0; i < NUM_POTS; i++)
|
||||
p_offset(i, -100);
|
||||
}
|
||||
|
||||
|
||||
int pot_get(int p)
|
||||
{
|
||||
return Levels[p];
|
||||
}
|
||||
|
||||
void pot_set(int p, int val)
|
||||
{
|
||||
int old = Levels[p];
|
||||
int off;
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
if (val > 100)
|
||||
val = 100;
|
||||
off = val - old;
|
||||
if (off == 0)
|
||||
return;
|
||||
pot_offset(p, off);
|
||||
}
|
||||
|
||||
|
||||
|
15
pot.h
Normal file
15
pot.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
#ifndef POT_H_INCLUDED
|
||||
#define POT_H_INCLUDED
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
void pot_init(void);
|
||||
int pot_get(int p);
|
||||
void pot_set(int p, int val);
|
||||
void pot_offset(int p, int offset);
|
||||
|
||||
#define pot_get_master() pot_get(2)
|
||||
#define pot_set_master(x) pot_set(2,x)
|
||||
|
||||
#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
|
212
startup.c
Normal file
212
startup.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* (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_rot0(void);
|
||||
//extern void isr_exti_rot1(void);
|
||||
extern void isr_exti_channel(void);
|
||||
extern void isr_exti_button(void);
|
||||
//extern void isr_tim1(void);
|
||||
//extern void isr_tim2(void);
|
||||
//extern void isr_tim3(void);
|
||||
extern void isr_tim4(void);
|
||||
extern void isr_systick(void);
|
||||
extern void otg_fs_isr(void);
|
||||
extern void usb_fs_wkup_isr(void);
|
||||
extern void dma1_stream5_isr(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_exti_button, // EXTI0_IRQ 6
|
||||
isr_exti_button, // EXTI1_IRQ 7
|
||||
isr_empty, // EXTI2_IRQ 8
|
||||
isr_exti_button, // EXTI3_IRQ 9
|
||||
isr_exti_rot0, // 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
|
||||
dma1_stream5_isr, // 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 // ROT-1
|
||||
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_tim4, // 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_empty, // EXTI15_10_IRQ 40
|
||||
isr_empty, // RTC_ALARM_IRQ 41
|
||||
usb_fs_wkup_isr, // 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
|
||||
isr_empty, // FSMC_IRQ
|
||||
isr_empty, // SDIO_IRQ
|
||||
isr_empty, // TIM5_IRQ
|
||||
isr_empty, // SPI3_IRQ
|
||||
isr_empty, // UART4_IRQ
|
||||
isr_empty, // UART5_IRQ
|
||||
isr_empty, // TIM6_DAC_IRQ
|
||||
isr_empty, // TIM7_IRQ
|
||||
isr_empty, // DMA2_STREAM0_IRQ
|
||||
isr_empty, // DMA2_STREAM1_IRQ
|
||||
isr_empty, // DMA2_STREAM2_IRQ
|
||||
isr_empty, // DMA2_STREAM3_IRQ
|
||||
isr_empty, // DMA2_STREAM4_IRQ
|
||||
isr_empty, // ETH_IRQ
|
||||
isr_empty, // ETH_WKUP_IRQ
|
||||
isr_empty, // CAN2_TX_IRQ
|
||||
isr_empty, // CAN2_RX0_IRQ
|
||||
isr_empty, // CAN2_RX1_IRQ
|
||||
isr_empty, // CAN2_SCE_IRQ
|
||||
otg_fs_isr, // OTG_FS_IRQ
|
||||
isr_empty, // DMA2_STREAM5_IRQ
|
||||
isr_empty, // DMA2_STREAM6_IRQ
|
||||
isr_empty, // DMA2_STREAM7_IRQ
|
||||
isr_empty, // USART6_IRQ
|
||||
isr_empty, // I2C3_EV_IRQ
|
||||
isr_empty, // I2C3_ER_IRQ
|
||||
isr_empty, // OTG_HS_EP1_OUT_IRQ
|
||||
isr_empty, // OTG_HS_EP1_IN_IRQ
|
||||
isr_empty, // OTG_HS_WKUP_IRQ
|
||||
isr_empty, // OTG_HS_IRQ
|
||||
isr_empty, // DCMI_IRQ
|
||||
isr_empty, // CRYP_IRQ
|
||||
isr_empty, // HASH_RNG_IRQ
|
||||
isr_empty, // FPU_IRQ
|
||||
isr_empty, // UART7_IRQ
|
||||
isr_empty, // UART8_IRQ
|
||||
isr_empty, // SPI4_IRQ
|
||||
isr_empty, // SPI5_IRQ
|
||||
isr_empty, // SPI6_IRQ
|
||||
isr_empty, // SAI1_IRQ
|
||||
isr_empty, // LCD_TFT_IRQ
|
||||
isr_empty, // LCD_TFT_ERR_IRQ
|
||||
isr_empty, // DMA2D_IRQ
|
||||
|
||||
};
|
170
system.c
Normal file
170
system.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "system.h"
|
||||
|
||||
|
||||
uint32_t cpu_freq = 168000000;
|
||||
/*** 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(void)
|
||||
{
|
||||
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 Speed = 168MHz) */
|
||||
pllm = 8;
|
||||
plln = 336;
|
||||
pllp = 2;
|
||||
pllq = 7;
|
||||
pllr = 0;
|
||||
hpre = RCC_PRESCALER_DIV_NONE;
|
||||
ppre1 = RCC_PRESCALER_DIV_4;
|
||||
ppre2 = RCC_PRESCALER_DIV_2;
|
||||
flash_waitstates = 3;
|
||||
|
||||
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 8MHz. */
|
||||
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 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 << 1) | (1 << 0))) != 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)
|
||||
;
|
||||
}
|
||||
|
559
system.h
Normal file
559
system.h
Normal file
|
@ -0,0 +1,559 @@
|
|||
#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);
|
||||
void printbin(const uint8_t *buf, int len); /* Defined in uart.c */
|
||||
|
||||
extern int _mutex_lock(void *); /* defined in mutex.S */
|
||||
extern int _mutex_unlock(void *);
|
||||
|
||||
/* PIN CONFIG TARGET */
|
||||
#define LED 0 // PE0
|
||||
|
||||
#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 TIM3_APB1_CLOCK_ER_VAL (1 << 1)
|
||||
#define TIM4_APB1_CLOCK_ER_VAL (1 << 2)
|
||||
#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 ADC1_APB2_CLOCK_ER_VAL (1 << 8)
|
||||
#define TIM1_APB2_CLOCK_ER_VAL (1 << 0)
|
||||
|
||||
#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(void);
|
||||
void clock_pll_off(void);
|
||||
|
||||
|
||||
/* NVIC */
|
||||
/* NVIC ISER Base register (Cortex-M) */
|
||||
#define NVIC_RTC_IRQ (3)
|
||||
#define NVIC_TIM1_IRQN (27)
|
||||
#define NVIC_TIM2_IRQN (28)
|
||||
#define NVIC_TIM3_IRQN (29)
|
||||
#define NVIC_TIM4_IRQN (30)
|
||||
#define NVIC_ISER_BASE (0xE000E100)
|
||||
#define NVIC_ICER_BASE (0xE000E180)
|
||||
#define NVIC_ICPR_BASE (0xE000E280)
|
||||
#define NVIC_IPRI_BASE (0xE000E400)
|
||||
#define NVIC_EXTI0_IRQ (6)
|
||||
#define NVIC_EXTI9_5_IRQ (23)
|
||||
#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 GPIOA GPIOA_BASE
|
||||
#define GPIOB GPIOB_BASE
|
||||
#define GPIOC GPIOC_BASE
|
||||
#define GPIOD GPIOD_BASE
|
||||
#define GPIOE GPIOE_BASE
|
||||
|
||||
#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 GPIOD_MODE (*(volatile uint32_t *)(GPIOD_BASE + 0x00))
|
||||
#define GPIOD_OTYPE (*(volatile uint32_t *)(GPIOD_BASE + 0x04))
|
||||
#define GPIOD_PUPD (*(volatile uint32_t *)(GPIOD_BASE + 0x0c))
|
||||
#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)
|
||||
|
||||
/* Timers */
|
||||
#define TIM1_BASE (0x40010000)
|
||||
#define TIM1_CR1 (*(volatile uint32_t *)(TIM1_BASE + 0x00))
|
||||
#define TIM1_DIER (*(volatile uint32_t *)(TIM1_BASE + 0x0c))
|
||||
#define TIM1_SR (*(volatile uint32_t *)(TIM1_BASE + 0x10))
|
||||
#define TIM1_EGR (*(volatile uint16_t *)(TIM1_BASE + 0x14))
|
||||
#define TIM1_CCMR1 (*(volatile uint16_t *)(TIM1_BASE + 0x18))
|
||||
#define TIM1_CCMR2 (*(volatile uint16_t *)(TIM1_BASE + 0x1c))
|
||||
#define TIM1_CCER (*(volatile uint16_t *)(TIM1_BASE + 0x20))
|
||||
#define TIM1_CNT (*(volatile uint16_t *)(TIM1_BASE + 0x24))
|
||||
#define TIM1_PSC (*(volatile uint16_t *)(TIM1_BASE + 0x28))
|
||||
#define TIM1_ARR (*(volatile uint16_t *)(TIM1_BASE + 0x2c))
|
||||
#define TIM1_CCR1 (*(volatile uint32_t *)(TIM1_BASE + 0x34))
|
||||
#define TIM1_CCR2 (*(volatile uint32_t *)(TIM1_BASE + 0x3C))
|
||||
#define TIM1_CCR3 (*(volatile uint32_t *)(TIM1_BASE + 0x38))
|
||||
#define TIM1_CCR4 (*(volatile uint32_t *)(TIM1_BASE + 0x40))
|
||||
|
||||
#define TIM2_BASE (0x40000000)
|
||||
#define TIM2_CR1 (*(volatile uint32_t *)(TIM2_BASE + 0x00))
|
||||
#define TIM2_DIER (*(volatile uint32_t *)(TIM2_BASE + 0x0c))
|
||||
#define TIM2_SR (*(volatile uint32_t *)(TIM2_BASE + 0x10))
|
||||
#define TIM2_EGR (*(volatile uint16_t *)(TIM2_BASE + 0x14))
|
||||
#define TIM2_CCMR1 (*(volatile uint16_t *)(TIM2_BASE + 0x18))
|
||||
#define TIM2_CCMR2 (*(volatile uint16_t *)(TIM2_BASE + 0x1c))
|
||||
#define TIM2_CCER (*(volatile uint16_t *)(TIM2_BASE + 0x20))
|
||||
#define TIM2_CNT (*(volatile uint32_t *)(TIM2_BASE + 0x24))
|
||||
#define TIM2_PSC (*(volatile uint32_t *)(TIM2_BASE + 0x28))
|
||||
#define TIM2_ARR (*(volatile uint32_t *)(TIM2_BASE + 0x2c))
|
||||
#define TIM2_CCR1 (*(volatile uint32_t *)(TIM2_BASE + 0x34))
|
||||
#define TIM2_CCR2 (*(volatile uint32_t *)(TIM2_BASE + 0x3C))
|
||||
#define TIM2_CCR3 (*(volatile uint32_t *)(TIM2_BASE + 0x38))
|
||||
#define TIM2_CCR4 (*(volatile uint32_t *)(TIM2_BASE + 0x40))
|
||||
|
||||
#define TIM3_BASE (0x40000400)
|
||||
#define TIM3_CR1 (*(volatile uint32_t *)(TIM3_BASE + 0x00))
|
||||
#define TIM3_DIER (*(volatile uint32_t *)(TIM3_BASE + 0x0c))
|
||||
#define TIM3_SR (*(volatile uint32_t *)(TIM3_BASE + 0x10))
|
||||
#define TIM3_EGR (*(volatile uint16_t *)(TIM3_BASE + 0x14))
|
||||
#define TIM3_CCMR1 (*(volatile uint16_t *)(TIM3_BASE + 0x18))
|
||||
#define TIM3_CCMR2 (*(volatile uint16_t *)(TIM3_BASE + 0x1c))
|
||||
#define TIM3_CCER (*(volatile uint16_t *)(TIM3_BASE + 0x20))
|
||||
#define TIM3_CNT (*(volatile uint16_t *)(TIM3_BASE + 0x24))
|
||||
#define TIM3_PSC (*(volatile uint16_t *)(TIM3_BASE + 0x28))
|
||||
#define TIM3_ARR (*(volatile uint16_t *)(TIM3_BASE + 0x2c))
|
||||
#define TIM3_CCR1 (*(volatile uint32_t *)(TIM3_BASE + 0x34))
|
||||
#define TIM3_CCR2 (*(volatile uint32_t *)(TIM3_BASE + 0x3C))
|
||||
#define TIM3_CCR3 (*(volatile uint32_t *)(TIM3_BASE + 0x38))
|
||||
#define TIM3_CCR4 (*(volatile uint32_t *)(TIM3_BASE + 0x40))
|
||||
|
||||
|
||||
#define TIM4_BASE (0x40000800)
|
||||
#define TIM4_CR1 (*(volatile uint32_t *)(TIM4_BASE + 0x00))
|
||||
#define TIM4_DIER (*(volatile uint32_t *)(TIM4_BASE + 0x0c))
|
||||
#define TIM4_SR (*(volatile uint32_t *)(TIM4_BASE + 0x10))
|
||||
#define TIM4_CCMR1 (*(volatile uint16_t *)(TIM4_BASE + 0x18))
|
||||
#define TIM4_CCMR2 (*(volatile uint16_t *)(TIM4_BASE + 0x1c))
|
||||
#define TIM4_CCER (*(volatile uint16_t *)(TIM4_BASE + 0x20))
|
||||
#define TIM4_CNT (*(volatile uint16_t *)(TIM4_BASE + 0x24))
|
||||
#define TIM4_PSC (*(volatile uint16_t *)(TIM4_BASE + 0x28))
|
||||
#define TIM4_ARR (*(volatile uint16_t *)(TIM4_BASE + 0x2c))
|
||||
|
||||
#define TIM_DIER_UIE (1 << 0)
|
||||
#define TIM_SR_UIF (1 << 0)
|
||||
#define TIM_CR1_CLOCK_ENABLE (1 << 0)
|
||||
#define TIM_CR1_UPD_RS (1 << 2)
|
||||
#define TIM_CR1_ARPE (1 << 7)
|
||||
|
||||
#define TIM_CCER_CC1_ENABLE (1 << 0)
|
||||
#define TIM_CCER_CC2_ENABLE (1 << 4)
|
||||
#define TIM_CCER_CC3_ENABLE (1 << 8)
|
||||
#define TIM_CCER_CC4_ENABLE (1 << 12)
|
||||
#define TIM_CCMR1_OC1M_PWM1 (0x06 << 4) | (1 << 3)
|
||||
#define TIM_CCMR1_OC2M_PWM1 (0x06 << 12) | (1 << 11)
|
||||
#define TIM_CCMR2_OC3M_PWM1 (0x06 << 4) | (1 << 3)
|
||||
#define TIM_CCMR2_OC4M_PWM1 (0x06 << 12) | (1 << 11)
|
||||
|
||||
#define AHB1_CLOCK_ER (*(volatile uint32_t *)(0x40023830))
|
||||
#define GPIOD_AHB1_CLOCK_ER (1 << 3)
|
||||
|
||||
|
||||
/* ADC */
|
||||
|
||||
#define ADC1_BASE (0x40012000)
|
||||
#define ADC_COM_BASE (0x40012300)
|
||||
#define ADC_COM_CCR (*(volatile uint32_t *)(ADC_COM_BASE + 0x04))
|
||||
#define ADC1_SR (*(volatile uint32_t *)(ADC1_BASE + 0x00))
|
||||
#define ADC1_CR1 (*(volatile uint32_t *)(ADC1_BASE + 0x04))
|
||||
#define ADC1_CR2 (*(volatile uint32_t *)(ADC1_BASE + 0x08))
|
||||
#define ADC1_SMPR1 (*(volatile uint32_t *)(ADC1_BASE + 0x0c))
|
||||
#define ADC1_SMPR2 (*(volatile uint32_t *)(ADC1_BASE + 0x10))
|
||||
#define ADC1_SQR3 (*(volatile uint32_t *)(ADC1_BASE + 0x34))
|
||||
#define ADC1_DR (*(volatile uint32_t *)(ADC1_BASE + 0x4c))
|
||||
#define ADC_CR1_SCAN (1 << 8)
|
||||
#define ADC_CR2_EN (1 << 0)
|
||||
#define ADC_CR2_CONT (1 << 1)
|
||||
#define ADC_CR2_SWSTART (1 << 30)
|
||||
#define ADC_SR_EOC (1 << 1)
|
||||
#define ADC_SMPR_SMP_480CYC (0x7)
|
||||
|
||||
/* Reboot */
|
||||
|
||||
#define AIRCR *(volatile uint32_t *)(0xE000ED0C)
|
||||
#define AIRCR_VKEY (0x05FA << 16)
|
||||
# define AIRCR_SYSRESETREQ (1 << 2)
|
||||
|
||||
static inline void reboot(void)
|
||||
{
|
||||
AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#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 - 0x100
|
||||
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));
|
57
timer.c
Normal file
57
timer.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include <stdint.h>
|
||||
#include "system.h"
|
||||
|
||||
static uint32_t master_clock = 0;
|
||||
|
||||
/* Timer 4: Use val 60000 with PSC 1400 for 1s tick (84 Mhz) */
|
||||
/* Timer 4: Use val 52500 with PSC 200 for 1/8 s tick (84 Mhz) */
|
||||
|
||||
#define TMR4_INIT_VAL 52500
|
||||
#define TMR4_INIT_PSC 200
|
||||
|
||||
void timer_init(void)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t psc = 1;
|
||||
uint32_t err = 0;
|
||||
|
||||
nvic_irq_enable(NVIC_TIM4_IRQN);
|
||||
nvic_irq_setprio(NVIC_TIM4_IRQN, 0);
|
||||
APB1_CLOCK_RST |= TIM4_APB1_CLOCK_ER_VAL;
|
||||
__asm__ volatile ("dmb");
|
||||
APB1_CLOCK_RST &= ~TIM4_APB1_CLOCK_ER_VAL;
|
||||
APB1_CLOCK_ER |= TIM4_APB1_CLOCK_ER_VAL;
|
||||
|
||||
TIM4_CR1 = 0;
|
||||
__asm__ volatile ("dmb");
|
||||
TIM4_PSC = TMR4_INIT_PSC;
|
||||
TIM4_ARR = TMR4_INIT_VAL;
|
||||
TIM4_CR1 |= TIM_CR1_CLOCK_ENABLE;
|
||||
TIM4_DIER |= TIM_DIER_UIE;
|
||||
__asm__ volatile ("dmb");
|
||||
}
|
||||
|
||||
static volatile uint32_t tim4_ticks = 0;
|
||||
void isr_tim1(void)
|
||||
{
|
||||
TIM1_SR &= ~TIM_SR_UIF;
|
||||
}
|
||||
|
||||
void isr_tim3(void)
|
||||
{
|
||||
TIM3_SR &= ~TIM_SR_UIF;
|
||||
}
|
||||
|
||||
void isr_tim4(void)
|
||||
{
|
||||
TIM4_SR &= ~TIM_SR_UIF;
|
||||
tim4_ticks++;
|
||||
}
|
||||
|
||||
void gettime(uint32_t *seconds, uint32_t *microseconds)
|
||||
{
|
||||
*microseconds = ((TIM4_CNT * TMR4_INIT_PSC) / 84) + (tim4_ticks & 0x07) * 125000;
|
||||
*seconds = (tim4_ticks >> 3);
|
||||
}
|
||||
|
||||
|
142
uart.c
Normal file
142
uart.c
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* (c) danielinux 2019
|
||||
*
|
||||
* GPLv.2
|
||||
*
|
||||
* See LICENSE for details
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.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 | UART_CR1_RX_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;
|
||||
}
|
||||
|
||||
char uart_read(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
reg = UART2_SR;
|
||||
if (reg & UART_SR_RX_NOTEMPTY)
|
||||
return (char)(UART2_DR);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* commodity to print binary buffers */
|
||||
|
||||
void printbin(const uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((i % 16) == 0)
|
||||
printf("\r\n%08x: ", i);
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
|
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
|
181
ui.c
Normal file
181
ui.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* (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 <stdio.h>
|
||||
#include "ui.h"
|
||||
|
||||
|
||||
/* Uncomment for device initialization */
|
||||
//#define DEVICE_INITIALIZATION
|
||||
|
||||
static const char welcome_message0[]= " Waveblender ";
|
||||
static const char welcome_message1[]= " (c) 2020 ";
|
||||
static const char welcome_message2[]= " danielinux ";
|
||||
|
||||
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 int sleeping = 0;
|
||||
|
||||
static char password[MAX_PASSWORD] = {};
|
||||
static int pin_idx = 0;
|
||||
|
||||
|
||||
#define SLEEP_TIME (5000)
|
||||
|
||||
static void ui_sleep(void)
|
||||
{
|
||||
display_scroll(NULL, 0);
|
||||
display_clear(NULL);
|
||||
sleeping = 1;
|
||||
}
|
||||
|
||||
static int ui_wakeup(void)
|
||||
{
|
||||
last_action = jiffies;
|
||||
if (sleeping) {
|
||||
sleeping = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ui_msg(const char *txt)
|
||||
{
|
||||
ui_wakeup();
|
||||
display_scroll(NULL, 0);
|
||||
display_clear(NULL);
|
||||
display_text(6, txt);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t display_cur_v = 0;
|
||||
static uint8_t menu_selection = 0;
|
||||
|
||||
void ui_menu_autoscroll(void)
|
||||
{
|
||||
int lines = CurrentMenu->entry_n;
|
||||
if ((lines < 5) || (menu_selection < 2))
|
||||
display_cur_v = 0;
|
||||
else if (menu_selection > lines - 2)
|
||||
display_cur_v = 0x40 - ((lines - 4) * 8);
|
||||
else
|
||||
display_cur_v = 0x40 - ((menu_selection - 2) * 8);
|
||||
display_scroll(NULL, display_cur_v);
|
||||
}
|
||||
|
||||
static void ui_display_menu_refresh(void)
|
||||
{
|
||||
const struct display_menu *menu = CurrentMenu;
|
||||
uint8_t vline;
|
||||
int i;
|
||||
display_scroll(NULL, display_cur_v);
|
||||
display_clear(NULL);
|
||||
|
||||
for (i = 0; i < menu->entry_n; i++) {
|
||||
vline = i + 4;
|
||||
if (vline > 7)
|
||||
vline -= 8;
|
||||
if (i == menu_selection)
|
||||
display_text_inverse(vline, menu->entry[i].title);
|
||||
else
|
||||
display_text(vline, menu->entry[i].title);
|
||||
}
|
||||
WFI();
|
||||
}
|
||||
|
||||
void ui_display_menu(const struct display_menu *menu)
|
||||
{
|
||||
uint8_t i;
|
||||
display_clear(NULL);
|
||||
menu_selection = 0;
|
||||
display_cur_v = 0;
|
||||
CurrentMenu = (struct display_menu *)menu;
|
||||
ui_display_menu_refresh();
|
||||
}
|
||||
|
||||
void ui_button_press(uint8_t b, int hold)
|
||||
{
|
||||
if (b == '+') {
|
||||
int n = menu_selection;
|
||||
menu_selection = 0;
|
||||
if (CurrentMenu->entry[n].action) {
|
||||
display_cur_v = 0;
|
||||
display_clear(NULL);
|
||||
display_scroll(NULL, display_cur_v);
|
||||
CurrentMenu->entry[n].action(
|
||||
CurrentMenu->entry[n].arg);
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (b == 'U') {
|
||||
if (menu_selection > 0) {
|
||||
menu_selection--;
|
||||
ui_menu_autoscroll();
|
||||
ui_display_menu_refresh();
|
||||
}
|
||||
}
|
||||
if (b == 'D') {
|
||||
if (menu_selection < CurrentMenu->entry_n - 1) {
|
||||
menu_selection++;
|
||||
ui_menu_autoscroll();
|
||||
ui_display_menu_refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) < 30)
|
||||
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, display_cur_v);
|
||||
display_clear(NULL);
|
||||
display_setcontrast(NULL, 0xcf);
|
||||
ui_display_menu(CurrentMenu);
|
||||
now = jiffies;
|
||||
for (i = 1; i < 9; i++) {
|
||||
led_beat(i);
|
||||
while((jiffies - now < 100))
|
||||
WFI();
|
||||
now = jiffies;
|
||||
}
|
||||
}
|
||||
|
||||
void ui_keepalive(uint32_t timeslice)
|
||||
{
|
||||
}
|
32
ui.h
Normal file
32
ui.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef UI_H
|
||||
#define UI_H
|
||||
#include <stdint.h>
|
||||
|
||||
void ui_init(void);
|
||||
|
||||
struct display_menu {
|
||||
struct display_menu *next;
|
||||
int entry_n;
|
||||
struct display_menu_entry {
|
||||
char title[16];
|
||||
void (*action)(const void *arg);
|
||||
const void *arg;
|
||||
} entry[8];
|
||||
|
||||
};
|
||||
|
||||
const struct display_menu MainMenu, MeasureMenu, SignalGenMenu,
|
||||
ExtraMenu;
|
||||
|
||||
void ui_display_menu(const struct display_menu *menu);
|
||||
void ui_button_press(uint8_t b, int hold);
|
||||
|
||||
struct display_menu *CurrentMenu;
|
||||
|
||||
/* Defined in main to intercept input controls */
|
||||
void set_input_callback(void (*cb)(uint8_t press, int hold));
|
||||
void clear_input_callback(void);
|
||||
void set_keepalive(void (*cb)(void));
|
||||
void clear_keepalive(void);
|
||||
|
||||
#endif
|
268
ui_drone.c
Normal file
268
ui_drone.c
Normal file
|
@ -0,0 +1,268 @@
|
|||
#include <stddef.h>
|
||||
#include "ui.h"
|
||||
#include <string.h>
|
||||
#include "adc.h"
|
||||
#include "button.h"
|
||||
#include "system.h"
|
||||
#include "unicore-mx/stm32/gpio.h"
|
||||
#include "unicore-mx/stm32/rcc.h"
|
||||
#include "pot.h"
|
||||
|
||||
#define CENTER_X ((int)(52))
|
||||
#define CENTER_Y ((int)(50))
|
||||
#define NEUTRAL 2
|
||||
|
||||
struct display_menu *CurrentMenu = &MainMenu;
|
||||
|
||||
extern volatile uint32_t jiffies;
|
||||
static uint32_t drone_xy_gain = 1;
|
||||
|
||||
static void ui_return(uint8_t press, int hold)
|
||||
{
|
||||
display_clear(NULL);
|
||||
clear_input_callback();
|
||||
ui_display_menu(&MainMenu);
|
||||
}
|
||||
|
||||
static void ui_action_interrupt(uint8_t press, int hold)
|
||||
{
|
||||
if (press == '+') {
|
||||
clear_keepalive();
|
||||
display_clear(NULL);
|
||||
display_text(5, "Interrupted!");
|
||||
set_input_callback(ui_return);
|
||||
}
|
||||
}
|
||||
|
||||
static void display_drone(int line, uint16_t val)
|
||||
{
|
||||
char txt[] = "0000";
|
||||
if (val >= 1000)
|
||||
txt[0] = '0' + val / 1000;
|
||||
val %= 1000;
|
||||
if (val != 0)
|
||||
txt[3] = '0' + val % 10;
|
||||
if (val > 9)
|
||||
txt[2] = '0' + ((val / 10) % 10);
|
||||
if (val > 99)
|
||||
txt[1] = '0' + (val / 100);
|
||||
display_text(line, txt);
|
||||
}
|
||||
|
||||
static void display_volume(void)
|
||||
{
|
||||
char txt[4] = "000";
|
||||
int master_vol = pot_get_master();
|
||||
txt[0] = '0' + master_vol / 100;
|
||||
txt[1] = '0' + (master_vol % 100) / 10;
|
||||
txt[2] = '0' + (master_vol % 10);
|
||||
display_text(6, txt);
|
||||
}
|
||||
|
||||
void ui_drone_xy_poll(void)
|
||||
{
|
||||
uint16_t x = 0, y = 0;
|
||||
char TXT[]="Bender!";
|
||||
static uint32_t bend_update = 0;
|
||||
int X, Y;
|
||||
char bgain[4] = "000";
|
||||
rcc_periph_clock_enable(RCC_GPIOA);
|
||||
gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1 | GPIO2);
|
||||
adc_pin_val(2, &x);
|
||||
adc_pin_val(1, &y);
|
||||
X = (100 * x) / 4096;
|
||||
Y = (100 * y) / 4096;
|
||||
if (((X > CENTER_X) && ((X - CENTER_X) > NEUTRAL)) || ((X < CENTER_X) && ((CENTER_X - X) > NEUTRAL))) {
|
||||
int off = X - CENTER_X;
|
||||
pot_offset(0, off/10);
|
||||
}
|
||||
if (((Y > CENTER_Y) && ((Y - CENTER_Y) > NEUTRAL)) || ((Y < CENTER_Y) && ((CENTER_Y - Y) > NEUTRAL))) {
|
||||
int off = Y - CENTER_Y;
|
||||
pot_offset(1, off/10);
|
||||
}
|
||||
led_beat(((jiffies / 100) % 8) + 1);
|
||||
display_text(4, TXT);
|
||||
display_drone(5, pot_get(0));
|
||||
display_drone(6, pot_get(1));
|
||||
bgain[0] = '0' + drone_xy_gain / 100;
|
||||
bgain[1] = '0' + (drone_xy_gain % 100) / 10;
|
||||
bgain[2] = '0' + (drone_xy_gain % 10);
|
||||
display_text(7, bgain);
|
||||
}
|
||||
|
||||
void ui_bender_poll(void)
|
||||
{
|
||||
uint16_t x = 0, y = 0;
|
||||
char TXT[]="Bender!";
|
||||
static uint32_t bend_update = 0;
|
||||
int X, Y;
|
||||
char bgain[4] = "000";
|
||||
rcc_periph_clock_enable(RCC_GPIOA);
|
||||
gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1 | GPIO2);
|
||||
adc_pin_val(2, &x);
|
||||
adc_pin_val(1, &y);
|
||||
X = (100 * x) / 4096;
|
||||
Y = (100 * y) / 4096;
|
||||
pot_set(0, X);
|
||||
pot_set(1, Y);
|
||||
led_beat(((jiffies / 100) % 8) + 1);
|
||||
display_text(4, TXT);
|
||||
display_drone(5, pot_get(0));
|
||||
display_drone(6, pot_get(1));
|
||||
bgain[0] = '0' + drone_xy_gain / 100;
|
||||
bgain[1] = '0' + (drone_xy_gain % 100) / 10;
|
||||
bgain[2] = '0' + (drone_xy_gain % 10);
|
||||
display_text(7, bgain);
|
||||
}
|
||||
|
||||
static void ui_gain_input(uint8_t press, int hold)
|
||||
{
|
||||
if (press == '+') {
|
||||
display_clear(NULL);
|
||||
display_text(5, "Interrupted!");
|
||||
clear_keepalive();
|
||||
set_input_callback(ui_return);
|
||||
return;
|
||||
}
|
||||
if (press == 'U') {
|
||||
if (drone_xy_gain < 10)
|
||||
drone_xy_gain++;
|
||||
}
|
||||
if (press == 'D') {
|
||||
if (drone_xy_gain > 0)
|
||||
drone_xy_gain--;
|
||||
}
|
||||
ui_drone_xy_poll();
|
||||
}
|
||||
|
||||
|
||||
static void ui_drone_xy(const void *arg)
|
||||
{
|
||||
set_input_callback(ui_gain_input);
|
||||
set_keepalive(ui_drone_xy_poll);
|
||||
display_clear(NULL);
|
||||
ui_drone_xy_poll();
|
||||
}
|
||||
|
||||
static void ui_bender(const void *arg)
|
||||
{
|
||||
set_input_callback(ui_gain_input);
|
||||
set_keepalive(ui_bender_poll);
|
||||
display_clear(NULL);
|
||||
ui_bender_poll();
|
||||
}
|
||||
|
||||
|
||||
static void ui_mastervol_input(uint8_t press, int hold)
|
||||
{
|
||||
int master_vol = pot_get_master();
|
||||
if (press == 'U')
|
||||
if (master_vol < 1000)
|
||||
pot_set_master(master_vol + 5);
|
||||
|
||||
if (press == 'D') {
|
||||
if (master_vol > 4)
|
||||
pot_set_master(master_vol - 5);
|
||||
}
|
||||
if (press == '+') {
|
||||
display_clear(NULL);
|
||||
clear_input_callback();
|
||||
ui_display_menu(&MainMenu);
|
||||
return;
|
||||
}
|
||||
display_text(5, "Master Volume");
|
||||
display_volume();
|
||||
}
|
||||
|
||||
static void ui_mastervol(const void *arg)
|
||||
{
|
||||
set_input_callback(ui_mastervol_input);
|
||||
display_clear(NULL);
|
||||
display_text(5, "Master Volume");
|
||||
display_volume();
|
||||
}
|
||||
|
||||
|
||||
static void ui_bytebeat_input(uint8_t press, int hold) {
|
||||
if (press == '+') {
|
||||
display_clear(NULL);
|
||||
clear_input_callback();
|
||||
clear_keepalive();
|
||||
ui_display_menu(&MainMenu);
|
||||
}
|
||||
}
|
||||
|
||||
#define PLAY_SIZE 512
|
||||
|
||||
static uint8_t bb_buffer[PLAY_SIZE];
|
||||
|
||||
void ui_bytebeat_keepalive(void)
|
||||
{
|
||||
static uint32_t t = 0;
|
||||
int r = 0;
|
||||
if (dac_space() >= PLAY_SIZE) {
|
||||
for(;;t++) {
|
||||
bb_buffer[r++] = (t<<1)|(t>>4)*(((t>>12)|(t>>13)|(t>>6) | ((t>>2)|(t>>4))|(t<<1)|(t<<12)|((t<<5)&~(t>>22))));
|
||||
if (r >= PLAY_SIZE) {
|
||||
dac_write(bb_buffer, r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_bytebeat(const void *arg)
|
||||
{
|
||||
set_input_callback(ui_bytebeat_input);
|
||||
display_clear(NULL);
|
||||
display_text(5, " Bytebeat! ");
|
||||
set_keepalive(ui_bytebeat_keepalive);
|
||||
}
|
||||
|
||||
|
||||
static void ui_submenu(const void *arg)
|
||||
{
|
||||
ui_display_menu(arg);
|
||||
}
|
||||
|
||||
const struct display_menu PatternMenu = {
|
||||
.entry_n = 1,
|
||||
.entry = {
|
||||
{ "TODO! ", ui_submenu, &MainMenu},
|
||||
{ "", NULL, NULL}
|
||||
}
|
||||
};
|
||||
|
||||
const struct display_menu DroneMenu = {
|
||||
.entry_n = 2,
|
||||
.entry = {
|
||||
{ "Drone X, Y ", ui_drone_xy, NULL},
|
||||
{ "Bender ", ui_bender, NULL},
|
||||
{ "", NULL, NULL}
|
||||
}
|
||||
};
|
||||
|
||||
const struct display_menu SettingsMenu = {
|
||||
.entry_n = 1,
|
||||
.entry = {
|
||||
{ "TODO", ui_submenu, &MainMenu },
|
||||
{ "", NULL, NULL}
|
||||
}
|
||||
};
|
||||
|
||||
const struct display_menu MainMenu = {
|
||||
.entry_n = 5,
|
||||
.entry = {
|
||||
{ "Master Volume ", ui_mastervol, NULL },
|
||||
{ "Settings ", ui_submenu, &SettingsMenu },
|
||||
{ "Pattern ", ui_submenu, &PatternMenu },
|
||||
{ "Drone ", ui_submenu, &DroneMenu},
|
||||
{ "Bytebeat ", ui_bytebeat },
|
||||
{ "", NULL, NULL}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in a new issue