.
675 |
--------------------------------------------------------------------------------
/LICENSE_cc-by-sa.txt:
--------------------------------------------------------------------------------
1 | Attribution-ShareAlike 4.0 International
2 |
3 | =======================================================================
4 |
5 | Creative Commons Corporation ("Creative Commons") is not a law firm and
6 | does not provide legal services or legal advice. Distribution of
7 | Creative Commons public licenses does not create a lawyer-client or
8 | other relationship. Creative Commons makes its licenses and related
9 | information available on an "as-is" basis. Creative Commons gives no
10 | warranties regarding its licenses, any material licensed under their
11 | terms and conditions, or any related information. Creative Commons
12 | disclaims all liability for damages resulting from their use to the
13 | fullest extent possible.
14 |
15 | Using Creative Commons Public Licenses
16 |
17 | Creative Commons public licenses provide a standard set of terms and
18 | conditions that creators and other rights holders may use to share
19 | original works of authorship and other material subject to copyright
20 | and certain other rights specified in the public license below. The
21 | following considerations are for informational purposes only, are not
22 | exhaustive, and do not form part of our licenses.
23 |
24 | Considerations for licensors: Our public licenses are
25 | intended for use by those authorized to give the public
26 | permission to use material in ways otherwise restricted by
27 | copyright and certain other rights. Our licenses are
28 | irrevocable. Licensors should read and understand the terms
29 | and conditions of the license they choose before applying it.
30 | Licensors should also secure all rights necessary before
31 | applying our licenses so that the public can reuse the
32 | material as expected. Licensors should clearly mark any
33 | material not subject to the license. This includes other CC-
34 | licensed material, or material used under an exception or
35 | limitation to copyright. More considerations for licensors:
36 | wiki.creativecommons.org/Considerations_for_licensors
37 |
38 | Considerations for the public: By using one of our public
39 | licenses, a licensor grants the public permission to use the
40 | licensed material under specified terms and conditions. If
41 | the licensor's permission is not necessary for any reason--for
42 | example, because of any applicable exception or limitation to
43 | copyright--then that use is not regulated by the license. Our
44 | licenses grant only permissions under copyright and certain
45 | other rights that a licensor has authority to grant. Use of
46 | the licensed material may still be restricted for other
47 | reasons, including because others have copyright or other
48 | rights in the material. A licensor may make special requests,
49 | such as asking that all changes be marked or described.
50 | Although not required by our licenses, you are encouraged to
51 | respect those requests where reasonable. More considerations
52 | for the public:
53 | wiki.creativecommons.org/Considerations_for_licensees
54 |
55 | =======================================================================
56 |
57 | Creative Commons Attribution-ShareAlike 4.0 International Public
58 | License
59 |
60 | By exercising the Licensed Rights (defined below), You accept and agree
61 | to be bound by the terms and conditions of this Creative Commons
62 | Attribution-ShareAlike 4.0 International Public License ("Public
63 | License"). To the extent this Public License may be interpreted as a
64 | contract, You are granted the Licensed Rights in consideration of Your
65 | acceptance of these terms and conditions, and the Licensor grants You
66 | such rights in consideration of benefits the Licensor receives from
67 | making the Licensed Material available under these terms and
68 | conditions.
69 |
70 |
71 | Section 1 -- Definitions.
72 |
73 | a. Adapted Material means material subject to Copyright and Similar
74 | Rights that is derived from or based upon the Licensed Material
75 | and in which the Licensed Material is translated, altered,
76 | arranged, transformed, or otherwise modified in a manner requiring
77 | permission under the Copyright and Similar Rights held by the
78 | Licensor. For purposes of this Public License, where the Licensed
79 | Material is a musical work, performance, or sound recording,
80 | Adapted Material is always produced where the Licensed Material is
81 | synched in timed relation with a moving image.
82 |
83 | b. Adapter's License means the license You apply to Your Copyright
84 | and Similar Rights in Your contributions to Adapted Material in
85 | accordance with the terms and conditions of this Public License.
86 |
87 | c. BY-SA Compatible License means a license listed at
88 | creativecommons.org/compatiblelicenses, approved by Creative
89 | Commons as essentially the equivalent of this Public License.
90 |
91 | d. Copyright and Similar Rights means copyright and/or similar rights
92 | closely related to copyright including, without limitation,
93 | performance, broadcast, sound recording, and Sui Generis Database
94 | Rights, without regard to how the rights are labeled or
95 | categorized. For purposes of this Public License, the rights
96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
97 | Rights.
98 |
99 | e. Effective Technological Measures means those measures that, in the
100 | absence of proper authority, may not be circumvented under laws
101 | fulfilling obligations under Article 11 of the WIPO Copyright
102 | Treaty adopted on December 20, 1996, and/or similar international
103 | agreements.
104 |
105 | f. Exceptions and Limitations means fair use, fair dealing, and/or
106 | any other exception or limitation to Copyright and Similar Rights
107 | that applies to Your use of the Licensed Material.
108 |
109 | g. License Elements means the license attributes listed in the name
110 | of a Creative Commons Public License. The License Elements of this
111 | Public License are Attribution and ShareAlike.
112 |
113 | h. Licensed Material means the artistic or literary work, database,
114 | or other material to which the Licensor applied this Public
115 | License.
116 |
117 | i. Licensed Rights means the rights granted to You subject to the
118 | terms and conditions of this Public License, which are limited to
119 | all Copyright and Similar Rights that apply to Your use of the
120 | Licensed Material and that the Licensor has authority to license.
121 |
122 | j. Licensor means the individual(s) or entity(ies) granting rights
123 | under this Public License.
124 |
125 | k. Share means to provide material to the public by any means or
126 | process that requires permission under the Licensed Rights, such
127 | as reproduction, public display, public performance, distribution,
128 | dissemination, communication, or importation, and to make material
129 | available to the public including in ways that members of the
130 | public may access the material from a place and at a time
131 | individually chosen by them.
132 |
133 | l. Sui Generis Database Rights means rights other than copyright
134 | resulting from Directive 96/9/EC of the European Parliament and of
135 | the Council of 11 March 1996 on the legal protection of databases,
136 | as amended and/or succeeded, as well as other essentially
137 | equivalent rights anywhere in the world.
138 |
139 | m. You means the individual or entity exercising the Licensed Rights
140 | under this Public License. Your has a corresponding meaning.
141 |
142 |
143 | Section 2 -- Scope.
144 |
145 | a. License grant.
146 |
147 | 1. Subject to the terms and conditions of this Public License,
148 | the Licensor hereby grants You a worldwide, royalty-free,
149 | non-sublicensable, non-exclusive, irrevocable license to
150 | exercise the Licensed Rights in the Licensed Material to:
151 |
152 | a. reproduce and Share the Licensed Material, in whole or
153 | in part; and
154 |
155 | b. produce, reproduce, and Share Adapted Material.
156 |
157 | 2. Exceptions and Limitations. For the avoidance of doubt, where
158 | Exceptions and Limitations apply to Your use, this Public
159 | License does not apply, and You do not need to comply with
160 | its terms and conditions.
161 |
162 | 3. Term. The term of this Public License is specified in Section
163 | 6(a).
164 |
165 | 4. Media and formats; technical modifications allowed. The
166 | Licensor authorizes You to exercise the Licensed Rights in
167 | all media and formats whether now known or hereafter created,
168 | and to make technical modifications necessary to do so. The
169 | Licensor waives and/or agrees not to assert any right or
170 | authority to forbid You from making technical modifications
171 | necessary to exercise the Licensed Rights, including
172 | technical modifications necessary to circumvent Effective
173 | Technological Measures. For purposes of this Public License,
174 | simply making modifications authorized by this Section 2(a)
175 | (4) never produces Adapted Material.
176 |
177 | 5. Downstream recipients.
178 |
179 | a. Offer from the Licensor -- Licensed Material. Every
180 | recipient of the Licensed Material automatically
181 | receives an offer from the Licensor to exercise the
182 | Licensed Rights under the terms and conditions of this
183 | Public License.
184 |
185 | b. Additional offer from the Licensor -- Adapted Material.
186 | Every recipient of Adapted Material from You
187 | automatically receives an offer from the Licensor to
188 | exercise the Licensed Rights in the Adapted Material
189 | under the conditions of the Adapter's License You apply.
190 |
191 | c. No downstream restrictions. You may not offer or impose
192 | any additional or different terms or conditions on, or
193 | apply any Effective Technological Measures to, the
194 | Licensed Material if doing so restricts exercise of the
195 | Licensed Rights by any recipient of the Licensed
196 | Material.
197 |
198 | 6. No endorsement. Nothing in this Public License constitutes or
199 | may be construed as permission to assert or imply that You
200 | are, or that Your use of the Licensed Material is, connected
201 | with, or sponsored, endorsed, or granted official status by,
202 | the Licensor or others designated to receive attribution as
203 | provided in Section 3(a)(1)(A)(i).
204 |
205 | b. Other rights.
206 |
207 | 1. Moral rights, such as the right of integrity, are not
208 | licensed under this Public License, nor are publicity,
209 | privacy, and/or other similar personality rights; however, to
210 | the extent possible, the Licensor waives and/or agrees not to
211 | assert any such rights held by the Licensor to the limited
212 | extent necessary to allow You to exercise the Licensed
213 | Rights, but not otherwise.
214 |
215 | 2. Patent and trademark rights are not licensed under this
216 | Public License.
217 |
218 | 3. To the extent possible, the Licensor waives any right to
219 | collect royalties from You for the exercise of the Licensed
220 | Rights, whether directly or through a collecting society
221 | under any voluntary or waivable statutory or compulsory
222 | licensing scheme. In all other cases the Licensor expressly
223 | reserves any right to collect such royalties.
224 |
225 |
226 | Section 3 -- License Conditions.
227 |
228 | Your exercise of the Licensed Rights is expressly made subject to the
229 | following conditions.
230 |
231 | a. Attribution.
232 |
233 | 1. If You Share the Licensed Material (including in modified
234 | form), You must:
235 |
236 | a. retain the following if it is supplied by the Licensor
237 | with the Licensed Material:
238 |
239 | i. identification of the creator(s) of the Licensed
240 | Material and any others designated to receive
241 | attribution, in any reasonable manner requested by
242 | the Licensor (including by pseudonym if
243 | designated);
244 |
245 | ii. a copyright notice;
246 |
247 | iii. a notice that refers to this Public License;
248 |
249 | iv. a notice that refers to the disclaimer of
250 | warranties;
251 |
252 | v. a URI or hyperlink to the Licensed Material to the
253 | extent reasonably practicable;
254 |
255 | b. indicate if You modified the Licensed Material and
256 | retain an indication of any previous modifications; and
257 |
258 | c. indicate the Licensed Material is licensed under this
259 | Public License, and include the text of, or the URI or
260 | hyperlink to, this Public License.
261 |
262 | 2. You may satisfy the conditions in Section 3(a)(1) in any
263 | reasonable manner based on the medium, means, and context in
264 | which You Share the Licensed Material. For example, it may be
265 | reasonable to satisfy the conditions by providing a URI or
266 | hyperlink to a resource that includes the required
267 | information.
268 |
269 | 3. If requested by the Licensor, You must remove any of the
270 | information required by Section 3(a)(1)(A) to the extent
271 | reasonably practicable.
272 |
273 | b. ShareAlike.
274 |
275 | In addition to the conditions in Section 3(a), if You Share
276 | Adapted Material You produce, the following conditions also apply.
277 |
278 | 1. The Adapter's License You apply must be a Creative Commons
279 | license with the same License Elements, this version or
280 | later, or a BY-SA Compatible License.
281 |
282 | 2. You must include the text of, or the URI or hyperlink to, the
283 | Adapter's License You apply. You may satisfy this condition
284 | in any reasonable manner based on the medium, means, and
285 | context in which You Share Adapted Material.
286 |
287 | 3. You may not offer or impose any additional or different terms
288 | or conditions on, or apply any Effective Technological
289 | Measures to, Adapted Material that restrict exercise of the
290 | rights granted under the Adapter's License You apply.
291 |
292 |
293 | Section 4 -- Sui Generis Database Rights.
294 |
295 | Where the Licensed Rights include Sui Generis Database Rights that
296 | apply to Your use of the Licensed Material:
297 |
298 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
299 | to extract, reuse, reproduce, and Share all or a substantial
300 | portion of the contents of the database;
301 |
302 | b. if You include all or a substantial portion of the database
303 | contents in a database in which You have Sui Generis Database
304 | Rights, then the database in which You have Sui Generis Database
305 | Rights (but not its individual contents) is Adapted Material,
306 |
307 | including for purposes of Section 3(b); and
308 | c. You must comply with the conditions in Section 3(a) if You Share
309 | all or a substantial portion of the contents of the database.
310 |
311 | For the avoidance of doubt, this Section 4 supplements and does not
312 | replace Your obligations under this Public License where the Licensed
313 | Rights include other Copyright and Similar Rights.
314 |
315 |
316 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
317 |
318 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
319 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
320 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
321 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
322 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
323 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
324 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
325 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
326 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
327 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
328 |
329 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
330 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
331 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
332 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
333 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
334 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
335 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
336 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
337 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
338 |
339 | c. The disclaimer of warranties and limitation of liability provided
340 | above shall be interpreted in a manner that, to the extent
341 | possible, most closely approximates an absolute disclaimer and
342 | waiver of all liability.
343 |
344 |
345 | Section 6 -- Term and Termination.
346 |
347 | a. This Public License applies for the term of the Copyright and
348 | Similar Rights licensed here. However, if You fail to comply with
349 | this Public License, then Your rights under this Public License
350 | terminate automatically.
351 |
352 | b. Where Your right to use the Licensed Material has terminated under
353 | Section 6(a), it reinstates:
354 |
355 | 1. automatically as of the date the violation is cured, provided
356 | it is cured within 30 days of Your discovery of the
357 | violation; or
358 |
359 | 2. upon express reinstatement by the Licensor.
360 |
361 | For the avoidance of doubt, this Section 6(b) does not affect any
362 | right the Licensor may have to seek remedies for Your violations
363 | of this Public License.
364 |
365 | c. For the avoidance of doubt, the Licensor may also offer the
366 | Licensed Material under separate terms or conditions or stop
367 | distributing the Licensed Material at any time; however, doing so
368 | will not terminate this Public License.
369 |
370 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
371 | License.
372 |
373 |
374 | Section 7 -- Other Terms and Conditions.
375 |
376 | a. The Licensor shall not be bound by any additional or different
377 | terms or conditions communicated by You unless expressly agreed.
378 |
379 | b. Any arrangements, understandings, or agreements regarding the
380 | Licensed Material not stated herein are separate from and
381 | independent of the terms and conditions of this Public License.
382 |
383 |
384 | Section 8 -- Interpretation.
385 |
386 | a. For the avoidance of doubt, this Public License does not, and
387 | shall not be interpreted to, reduce, limit, restrict, or impose
388 | conditions on any use of the Licensed Material that could lawfully
389 | be made without permission under this Public License.
390 |
391 | b. To the extent possible, if any provision of this Public License is
392 | deemed unenforceable, it shall be automatically reformed to the
393 | minimum extent necessary to make it enforceable. If the provision
394 | cannot be reformed, it shall be severed from this Public License
395 | without affecting the enforceability of the remaining terms and
396 | conditions.
397 |
398 | c. No term or condition of this Public License will be waived and no
399 | failure to comply consented to unless expressly agreed to by the
400 | Licensor.
401 |
402 | d. Nothing in this Public License constitutes or may be interpreted
403 | as a limitation upon, or waiver of, any privileges and immunities
404 | that apply to the Licensor or You, including from the legal
405 | processes of any jurisdiction or authority.
406 |
407 |
408 | =======================================================================
409 |
410 | Creative Commons is not a party to its public
411 | licenses. Notwithstanding, Creative Commons may elect to apply one of
412 | its public licenses to material it publishes and in those instances
413 | will be considered the “Licensor.” The text of the Creative Commons
414 | public licenses is dedicated to the public domain under the CC0 Public
415 | Domain Dedication. Except for the limited purpose of indicating that
416 | material is shared under a Creative Commons public license or as
417 | otherwise permitted by the Creative Commons policies published at
418 | creativecommons.org/policies, Creative Commons does not authorize the
419 | use of the trademark "Creative Commons" or any other trademark or logo
420 | of Creative Commons without its prior written consent including,
421 | without limitation, in connection with any unauthorized modifications
422 | to any of its public licenses or any other arrangements,
423 | understandings, or agreements concerning use of licensed material. For
424 | the avoidance of doubt, this paragraph does not form part of the
425 | public licenses.
426 |
427 | Creative Commons may be contacted at creativecommons.org.
428 |
429 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | all: charlieplex.elf markoplex.elf
2 |
3 | SWITCHABLE_KEYPAD ?= D
4 | USE_DISPLAY ?= D
5 |
6 | ifeq ($(SWITCHABLE_KEYPAD), D)
7 | $(info SWITCHABLE_KEYPAD is enabled)
8 | endif
9 |
10 | ifeq ($(USE_DISPLAY), D)
11 | $(info USE_DISPLAY is enabled)
12 | DISPLAY_OBJ := display.o
13 | endif
14 |
15 | CHARL_OBJS = main.o charlieplex.o $(DISPLAY_OBJ)
16 | MARKO_OBJS = main.o markoplex.o $(DISPLAY_OBJ)
17 |
18 |
19 | DEBUG_FLAG ?= -g3
20 | OPTIMIZE_FLAG ?= -O0
21 |
22 |
23 |
24 | .PHONY: clean
25 | clean:
26 | rm -f *.o *.elf *.elf.map
27 |
28 | ifndef GCC_ARM_ROOT
29 | $(error set GCC_ARM_ROOT environment variable)
30 | endif
31 |
32 | export PATH := $(GCC_ARM_ROOT)/bin:$(PATH)
33 |
34 | CC = arm-none-eabi-gcc
35 | LD = arm-none-eabi-ld
36 |
37 |
38 | CONFIGURATION_FLAGS = -$(SWITCHABLE_KEYPAD)SWITCHABLE_KEYPAD \
39 | -$(USE_DISPLAY)USE_DISPLAY
40 |
41 | WARNINGS_FLAG = -Wextra -Wswitch --warn-no-return-type -Werror=return-type
42 | CC_ARM_FLAGS = -mthumb \
43 | -mcpu=cortex-m0plus \
44 | -D__VTOR_PRESENT \
45 | -mfloat-abi=softfp -D__SOFTFP__
46 | INIT_DEFINES = -DWEAK_FUNCTIONS
47 |
48 | GNU_ARM_LIBDIRS = -L$(GCC_ARM_ROOT)/arm-none-eabi/lib/thumb/v7e-m \
49 | -L$(GCC_ARM_ROOT)/lib/gcc/arm-none-eabi/6.3.1/thumb/v7e-m/fpv4-sp/softfp
50 |
51 |
52 |
53 | EXTRA_CC_FLAGS = -DLPC82X
54 |
55 | INIT_FILE = init/lpc8xx_ram_init
56 | LD_SCRIPT = ld/lpc824_ram.ld
57 |
58 | CCOPTS = -I./source \
59 | -I./include \
60 | -I./include/arm \
61 | -I./include/nxp \
62 | $(WARNINGS_FLAG) \
63 | $(DEBUG_FLAG) \
64 | $(CC_ARM_FLAGS) \
65 | $(INIT_DEFINES) \
66 | $(OPTIMIZE_FLAG) \
67 | $(EXTRA_CC_FLAGS) \
68 | $(CONFIGURATION_FLAGS)
69 |
70 | LD_ARM_FLAGS = -marmelf
71 | LINK_FLAGS = -static -M --print-memory-usage
72 | LDOPTS = $(LD_ARM_FLAGS) $(LINK_FLAGS)
73 |
74 |
75 | charlieplex.elf: $(CHARL_OBJS) $(INIT_FILE).o
76 | $(LD) -o $@ \
77 | $(LDOPTS) \
78 | $(CHARL_OBJS) \
79 | $(GNU_ARM_LIBDIRS) \
80 | $(INIT_FILE).o \
81 | -T $(LD_SCRIPT) \
82 | > $@.map
83 | tail -n 3 $@.map
84 |
85 | markoplex.elf: $(MARKO_OBJS) $(INIT_FILE).o
86 | $(LD) -o $@ \
87 | $(LDOPTS) \
88 | $(MARKO_OBJS) \
89 | $(GNU_ARM_LIBDIRS) \
90 | $(INIT_FILE).o \
91 | -T $(LD_SCRIPT) \
92 | > $@.map
93 | tail -n 3 $@.map
94 |
95 |
96 | vpath %.c source
97 |
98 |
99 | %.o: %.c
100 | $(CC) -c $(CCOPTS) $< -o $@
101 |
102 | charlieplex.o: source/charlieplex.c source/lpc824_bits.h
103 | display.o: source/display.c source/lpc824_bits.h
104 | main.o: source/main.c source/lpc824_bits.h
105 | markoplex.o: source/markoplex.c source/lpc824_bits.h
106 |
--------------------------------------------------------------------------------
/README.html:
--------------------------------------------------------------------------------
1 | markoplexing: ghostless N*(N-1) switch encoding
2 |
3 | markoplexing is a software extension to the well-known charlieplexing method of encoding of N*(N-1) input switches using only N I/O ports; however markoplexing distinguishes between real/actual vs spurious/“ghost” switch closures
4 |
5 | Contents
6 |
7 |
31 |
32 |
33 | “Claimer”
34 |
35 | (As opposed to “disclaimer”.)
36 |
37 | I claim, at minimum, that I independently conceived the technique contained herein. Therefore, in time-honored tradition, I am naming it after myself.
38 |
39 | I have searched online, on multiple occasions between September 2017 and the present date of February 5, 2019, without finding any mention of the technique; surprising given its simplicity. I am, however, aware that users of the largely broken patent and intellectual property systems often engage in the practice of “hiding” their work in order to better position themselves to instigate legal action.
40 |
41 | If presented with verifiable evidence of prior significant public disclosure of the technique, I will gladly share or cede credit with/to prior discoverers. This includes changing the name chosen here, to the extent practical. Likewise, I will somewhat less gladly comply with any legal claims of patent or intellectual property infringement, again to the extent practical; for example, even if removed in the future it would not be possible to retroactively change the fact that this repository was once available and may have been accessed.
42 |
43 | I believe the technique may be of use to practitioners in its field, and am therefore distributing it, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, under the terms of the licenses, below.
44 |
45 | Licenses
46 |
47 | This README.md document and machine-generated versions thereof, and the technique(s) it describes, is/are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International, also available at https://creativecommons.org/licenses/by-sa/4.0/.
48 |
49 | The software contained in this repository is licensed under the terms of the GNU General Public License, also available at https://www.gnu.org/licenses/gpl.html.
50 |
51 | Open Source shout-out
52 |
53 | All circuit diagrams were designed with Kicad/eeschema.
54 |
55 | All images were exported from Kicad/eeschema and edited (graphic lines and arrows added) using GIMP (and the ArrowCurved plugin).
56 |
57 | The physical circuit board was designed with Kicad/pcbnew.
58 |
59 | The example software implementation source code was written using GNU Emacs and compiled with the GCC ARM compiler.
60 |
61 | This README.md was written using GNU Emacs and tested with Discount/Markdown.
62 |
63 | Background material
64 |
65 | This section contains background explanations of microcontroller (MCU) switch interfacing, switch matrix encoding, and charlieplexing.
66 |
67 | Those familiar with MCU switch interfacing should skip ahead to MxN switch matrix encoding
68 |
69 | Those familiar with charlieplexing should skip ahead to Markoplexing
70 |
71 | Those understandably annoyed at being told what to skip should skip this entire repository. Note, however, that this is the last of the “skip” suggestions.
72 |
73 | MCU switch interfacing
74 |
75 | Physical switches are normally interfaced (connected) to microcontrollers and similar ICs using one of two slightly different methods.
76 |
77 | Since unconnected MCU input ports are subject to random electrical noise which can cause false readings, switches are usually connected in such a way that their associated input port is always in a known state regardless of whether the switch is open or closed.
78 |
79 | The two methods are:
80 |
81 |
82 | Logic low==true: The input port is connected to the positive voltage supply through a “pull up” resistor. The switch is also connected to the port, and when closed shorts it to ground. (The resistor prevents excess current flow.) When the switch is open the input port reads as high, and when closed low.
83 | Logic high==true: The input port is connected to the ground through a “pull down” resistor. The switch is also connected to the port, and when closed shorts it to the positive voltage supply. (Again the resistor prevents excess current flow.) When the switch is open the input port reads as low, and when closed high.
84 |
85 |
86 |
87 | Note that in both cases the resistors may be external, or internal to the MCU and enabled or disabled via software.
88 |
89 | The following figure illustrates a variation of these methods, in which instead of the switch being connected to power or ground it is connected to a separate MCU output port which provides the appropriate “switch open” voltage level. If that voltage is output, the switch input behaves as described above. If it is not – the output port is disabled to a high impedance state – the switch has no effect; however the input port remains in its known state via the pull-up/-down resistor.
90 |
91 | This method is not necessary (though it is still usable) for singly-connected switches. It is important for use with the switch matrix encoding schemes described below because it allows enabling and disabling the switches.
92 |
93 | 
94 |
95 | Logic==high in all examples
96 |
97 | Note that all examples in this README.md, and all code in this repository, assume high==true / pull-down resistors. The opposite could be used equally well, but would require reversing the polarity of the diodes in the circuit diagrams below.
98 |
99 | MxN switch matrix encoding
100 |
101 | Normally, interfacing N switches to a microcontroller would require N MCU input ports. While this is practical for small numbers of switches, it becomes unworkable as N becomes large.
102 |
103 | A common technique for interfacing large numbers of switches (such as a numeric keypad or particularly a PC keyboard) is to arrange M*N switches in an MxN rectangular matrix. In this way the M*N switches can be interfaced using only M+N I/O ports.
104 |
105 | Note that to get the greatest benefit from this scheme, M and N should be approximately equal, i.e. the rectangular matrix should be as square
106 | as possible. For example, 100 switches may be arranged in the following matrices:
107 |
108 | M N M*N M+N 100-(M+N) extras
109 | - --- --- --- --------- ------
110 | 1 100 100 101 -1
111 | 2 50 100 52 48
112 | 3 34 100 37 63 2
113 | 4 25 100 29 71
114 | 5 20 100 25 75
115 | 6 18 100 24 76 8
116 | 7 15 100 22 78 5
117 | 8 13 100 21 79 4
118 | 9 12 100 21 79 8
119 | 10 10 100 20 80
120 |
121 |
122 | The best benefit (80 fewer I/O ports) is achieved with the 10x10 matrix.
123 |
124 | Note also that the topological connections of the matrix need not match the physical layout/geometry of the switches.
125 |
126 | The following figure illustrates a 3x4 MxN matrix encoding for the common 12-key numeric keypad.
127 |
128 | 
129 |
130 | Scanning
131 |
132 | Matrix-encoded switches are read by MCU software using a scanning technique. The rows of the matrix are connected to MCU output ports, and the columns to input ports. (Note that the distinction between “rows” and “columns” is arbitrary – either dimension may be assigned arbitrarily as long as the assignments are consistent.)
133 |
134 | Scanning proceeds as follows:
135 |
136 |
137 | - All row outputs are initialized to inactive, high-impedance state.
138 | - Each row in turn is “energized” (set to high or low level, depending on the “logic true” level, pull-up/-down convention chosen; see above)
139 | - The states of the input ports are read. By correlating which row is energized with which input ports are “true”, the subset of switches which are closed is uniquely known.
140 | - The row output is de-energized.
141 | - Steps 2 through 4 are repeated until all rows have been energized, and all switch closures detected.
142 |
143 |
144 |
145 | One step of the scanning process is illustrated in the following figure. At the time shown, Row 2 is energized, which in combination with switch r2c3 (“row 2, column 3”) being closed causes the Column 3 input port to read “true” while Columns 1, 2, and 4 read “false”. Note that the closed states of switches r1c2, r3c1, and r3c4 have no effect as only Row 2 is energized. The red arrow line shows current flow from the Row 2 output to the Column 3 input.
146 |
147 | 
148 |
149 | Multiple closed switches in the same row are read similarly. In example below, Row 3 is energized and the closed switches r3c1 and r3c4 are simultaneously read on inputs Column 1 and Column 4
150 |
151 | 
152 |
153 | The “ghost” switch problem
154 |
155 | Unfortunately, matrix switch encoding has a significant flaw. If certain combinations of switches are closed simultaneously, the technique will spuriously read one or more open switches as closed.
156 |
157 | The following figure illustrates the problem. Switches r1c3, r1c4, and r2c4 are closed. When Row 1 is energized (not illustrated), switches r1c3 and r1c4 are correctly read on input ports Column 3 and Column 4.
158 |
159 | However, when Row 2 is energized as shown, current flows through switch r2c4 and is correctly detected at input port Column 4. But the current also flows “backwards” through switch r1c4 to row1, and from there through switch r1c3 to the Column 3 input port, as shown by the magenta arrow line.
160 |
161 | This causes the scanning software algorithm to falsely read switch r2c3 as closed when in fact it is not. This is colloquially known as a “ghost” switch closure because it as if some supernatural entity has closed the switch.
162 |
163 | 
164 |
165 | The diode fix for ghosting
166 |
167 | Fortunately, there is a simple fix for the “ghost” switch problem, although it requires additional hardware. By adding a diode in series with each switch, the “backward” current flow is stopped. The figure below is identical to the one above except for the additional diodes. The magenta arrow line shows current being prevented from flowing through switch r1c4 to Row 1, and switch r2c3 is not read as a ghost closure.
168 |
169 | 
170 |
171 | Charlieplexing
172 |
173 | “Charlieplexing” is a very clever scheme which allows interfacing N*(N-1) switches using only N I/O lines – typically far fewer than required by MxN matrix encoding. Note that the “I/O lines” distinction is important: In charlieplexing, ports must be dynamically switchable, sometimes being configured as inputs and at other times as outputs.
174 |
175 | A charlieplexed circuit for 12 switches interfaced with 4 lines (4*(4-3)==12
) is shown below. The circuit is best understood as having each of the I/O ports – when temporarily configured as an output – connected to 3 switches. The other sides of the switches are connected to one of the remaining 3 I/O ports, each of which is simultaneously/temporarily configured as an input.
176 |
177 | 
178 |
179 | Scanning is similar to the MxN matrix algorithm:
180 |
181 |
182 | - All ports are configured as inputs
183 | - Each port in turn configured as an output and “energized” (set to high or low level, depending on the “logic true” level, pull-up/-down convention chosen; see above).
184 | - The remaining ports are read. By correlating which port is the energized output with which input ports are “true”, the subset of switches which are closed is uniquely known.
185 | - The output port is de-energized and returned to “input” configuration.
186 | - Steps 2 through 4 are repeated until all ports have been output-energized, and all switch closures detected.
187 |
188 |
189 |
190 | The following figure shows scanning with port C configured as an output, and port D reading the switch 6 closure as an input
191 |
192 | 
193 |
194 | Similar to MxN matrices, multiple charlieplexed switches can be closed simultaneously and (sometimes! – see below) correctly read. In the following figure, switches 4 and 6 are closed and read correctly.
195 |
196 |
197 | 
198 |
199 | However, charlieplexing also suffers from ghost switch problems. The following figure shows current flowing from output port C, through switch 6, and being correctly detected at input port D. But since the switch 6 closure energizes the port D line, current flows “backwards” through closed switch 9, and then through switch 7 to input port A, just as it does when port D is intentionally energized and reading switch 1 of the 1-through-3 group. There is no way for port A to “know” the difference between this and the case where switch 4 is closed together with switch 6 as illustrated above, and switch 4 is read as a “ghost” closure.
200 |
201 | 
202 |
203 | As with MxN matrices, diodes can be added to prevent the backward flow and ghost switch misreads. The figure below illustrates this, with the flow through switch 9 being prevented by its associated diode, and the switch-7-read-as-ghost-switch-4 error avoided.
204 |
205 | 
206 |
207 | But a significant problem remains. The following figure illustrates a different kind of ghosting. Again, current flows correctly from output port C, through switch 6, and is detected at input port D. Also again, this energizes the port D line and current flows through switch 1 to input port A causing switch 4 to be falsely read as a ghost closure.
208 |
209 | 
210 |
211 | But as opposed to the situation with MxN matrices, where diodes fixed all ghosting problems, in charlieplexing they only prevent some “ghosts”. In the above example (among others), the incorrect current flow through switch 1 is in the “correct” direction, just as it would be when port D is energized to read switches 1 through 3. The following shows how the current passes through the diode and is still incorrectly read at port A.
212 |
213 |
214 | 
215 |
216 | This is the fatal flaw of charlieplexing. Note that it is “fatal” only if multiple switch closures need to be detected correctly and ghosts ignored. If the physical hardware only allows one switch closure at a time, or the system is allowed to reject cases when multiple switches are read (or mis-read) as closed, the flaw is unimportant.
217 |
218 | But if any and all combinations of multiple switches must be detected correctly (without ghosts), charlieplexing – and its benefit of reduced I/O port count – cannot be used. There is no way around the ghosting problem.
219 |
220 | Or is there?
221 |
222 | Markoplexing
223 |
224 | “Markoplexing” (see “Claimer”, above) is a very simple idea which distinguishes between real and ghost charlieplex switch closures. It is a software-only technique which requires no changes to the (diode-enhanced) charlieplex circuit topologies. This is achieved as follows …
225 |
226 | Observe that the two current flows, one correct and one “ghost”, in the final circuit diagram above. The correct one goes through diode 6 (and switch 6). The ghost current flows goes diode 6 … and diode 1.
227 |
228 | The correct input port sees the output port’s voltage minus one diode voltage drop. The incorrect/ghost port sees two diode drops.
229 |
230 | A-ha! What if, rather than configuring and reading the ports as digital inputs (true/false, one/zero) they are configured and read as analog inputs (voltage)? The difference between the voltage levels in the correct and ghost cases can then be detected, and the latter rejected.
231 |
232 | Charlieplex ghosting fixed!
233 |
234 | Note that this technique has several requirements:
235 |
236 |
237 | - A microcontroller with either analog-to-digital (ADC) or analog comparator inputs
238 | - … which can be dynamically switched between analog input and digital output modes.
239 | - Correct configuration of the analog voltage threshold between one vs more than one diode voltage drop
240 | - … diode voltage drops which, due to the very low currents passing through the high input impedance of the input ports, are not the canonically-spec’d value (typically 0.7V).
241 |
242 |
243 |
244 | Note also that, as tempting as it may seem, it is probably impossible to discriminate between the one and multiple diode voltage drops using a digital input port. Digital input ports always have thresholds for the detection of high and low logic levels with an “undefined” voltage zone in between.
245 |
246 | These levels are typically 0.3Vdd
, below which a logic 0 is read, and 0.7Vdd
above which is logic 1. There is no mathematically possible forward diode voltage drop Vf
which simultaneously satisfies the two required inequalities:
247 |
248 | Vdd - Vf > 0.7Vdd
249 | Vdd - 2Vf < 0.3Vdd
250 |
251 |
252 | Despite this, the required analog threshold can be adjusted by appropriate choice of diode, including Schottky for low Vf or light-emitting (LED) for high Vf.
253 |
254 | Debouncing and EMI
255 |
256 | Switch debouncing – ignoring the very rapid (sub-millisecond) opening and closing of switches due to their mechanical construction – is outside the scope of this document and repository. However, it may be possible to add capacitors to the switches to increase switch closure voltage rise time. Additionally, it may be possible to “ramp up” the output port voltage by using analog instead of digital outputs, which may in turn reduce edge-induced EMI caused by scanning. Both of these techniques could be used with digital inputs, but better results might be obtained with the analog input technique, particularly if the input ports have configurable hysteresis.
257 |
258 | Testing
259 |
260 | The “markoplexing” technique presented here is not merely a theoretical concept – it has been tested (and works as described) in a real-world demonstration.
261 |
262 | A 12-switch charlieplex circuit was constructed and tested using the markoplex technique. All 4096 possible switch combinations were not checked; those are far too many for manual testing and I have not had the time or resources to construct a testbed which uses solenoids, relays, transistors, opto-isolators, CMOS analog switches, etc. to automate the process.
263 |
264 | However, many specifically chosen multiple-closed-switch combinations were tested. All exhibited ghosting as expected with charlieplexing software, and none with markoplexing. More conclusively, all 12 possible permutations of “all switches closed except for one left open” were checked – if anything would cause ghosts those would (but with markoplexing did not).
265 |
266 | Example software implementation
267 |
268 | Included here is an example software implementation for the NXP LPC824 microcontroller chip. Both a charlieplexing and a markoplexing executable can be built to better compare the original and modified techniques.
269 |
270 | Also included is a primitive standalone build system for compiling the executables. Most users will probably want to extract only the basic code (contained in the source directory) for use in their own build environments.
271 |
272 | Basic constants describing I/O port (thus physical MCU pin) assignments, etc (many “etceteras”) are contained main.c, markoplex.c, and display.c source files. A differently connected LPC824 would require changing these. Of course a different MCU would require a complete rewrite of the code, which, in the interest of simplicity and clarity, is written in C and without attempts to make it generic or portable.
273 |
274 | If a 12 LED APA102 “smart” RGB strip is available it can be connected and driven by the LPC824’s SPI peripheral to display the detected switch closures (actual and/or ghost). See the file display.c and the #ifdef USE_DISPLAY
conditional compilation directive. If not, the included markcharl.gdb
file’s “dprintf” command can be used instead (or in addition).
275 |
276 | The #ifdef SWITCHABLE_KEYPAD
configuration is for use with the circuit, below.
277 |
278 | Configurable circuit (matrix/charlieplex)
279 |
280 | As an extra added bonus for the first 100 users to clone or download this repository (as well as any and all others – I have no plans to remove the circuit, I just like the sound of the marketing phrase “for the first 100”) will receive, free of charge, the following circuit diagram which can be configured via jumpers into either a 3x4 matrix or a 12-key/4-port charlieplex arrangement.
281 |
282 | The three 4-position headers shown as all jumpered represent an incorrect configuration. (I didn’t know how to draw headers/jumpers differently.) To use the circuit as a 3x4 matrix, connect the middle two pins (#2 and #3) of each of the three headers.
283 |
284 | To use it as for 12-key/4-port charlieplexing/markoplexing, connect the outer sets of pins (#1 to #2 and #3 to #4) on each header, and connect columns 1 through 4 to the four I/O ports. (The row 1 through 3 connections are unused in this configuration.) The switch numbers in this diagram map to the ones in the charlieplex diagrams above as:
285 |
286 | configurable charlieplex
287 | ------------ -----------
288 | Col1 D
289 | Col2 A
290 | Col3 B
291 | Col4 C
292 |
293 | r1c2 sw1 A
294 | r1c3 sw2 B
295 | r1c3 sw3 C
296 |
297 | r2c1 sw12 D
298 | r2c3 sw10 B
299 | r2c4 sw11 C
300 |
301 | r3c1 sw9 D
302 | r3c2 sw7 A
303 | r3c4 sw8 C
304 |
305 | r1c1 sw6 D
306 | r2c2 sw4 A
307 | r3c3 sw5 B
308 |
309 |
310 | This should be (somewhat) clear from tracing the circuit.
311 |
312 | Enjoy!
313 |
314 | 
315 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | markoplexing: ghostless N*(N-1) switch encoding
2 | ===============================================
3 |
4 | **markoplexing** is a software extension to the well-known **charlieplexing** method of encoding of __N*(N-1)__ input switches using only **N** I/O ports; however **markoplexing** distinguishes between real/actual vs spurious/"ghost" switch closures
5 |
6 |
7 |
8 |
9 | Contents
10 | --------
11 | * ["Claimer"](#claimer)
12 | * [Licenses](#licenses)
13 | * [Open Source shout-out](#open_source_shout_out)
14 | * [Background material](#background_material)
15 | * [MCU switch interfacing](#mcu_switch_interfacing)
16 | * [MxN switch matrix encoding](#mxn_switch_matrix_encoding)
17 | * [The "ghost" switch problem](#the_ghost_problem)
18 | * [The diode fix for ghosting](#the_diode_fix_for_ghosting)
19 | * [Charlieplexing](#charlieplexing)
20 | * [Markoplexing](#markoplexing)
21 | * [Debouncing and EMI](#debouncing_and_emi)
22 | * [Testing](#testing)
23 | * [Example software implementation](#example_software_implementation)
24 | * [Configurable circuit (matrix/charlieplex)](#configurable_circuit)
25 |
26 |
27 |
28 | "Claimer"
29 | ---------
30 |
31 | (As opposed to "disclaimer".)
32 |
33 | I claim, at minimum, that I independently conceived the technique contained herein. Therefore, in time-honored tradition, I am naming it after myself.
34 |
35 | I have searched online, on multiple occasions between September 2017 and the present date of February 5, 2019, without finding any mention of the technique; surprising given its simplicity. I am, however, aware that users of the largely broken patent and intellectual property systems often engage in the practice of "hiding" their work in order to better position themselves to instigate legal action.
36 |
37 | If presented with verifiable evidence of prior significant public disclosure of the technique, I will gladly share or cede credit with/to prior discoverers. This includes changing the name chosen here, to the extent practical. Likewise, I will somewhat less gladly comply with any legal claims of patent or intellectual property infringement, again to the extent practical; for example, even if removed in the future it would not be possible to retroactively change the fact that this repository was once available and may have been accessed.
38 |
39 | I believe the technique may be of use to practitioners in its field, and am therefore distributing it, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, under the terms of the [licenses](#licenses), below.
40 |
41 |
42 |
43 | Licenses
44 | --------
45 |
46 | This README.md document and machine-generated versions thereof, and the technique(s) it describes, is/are licensed under the terms of the Creative Commons [Attribution-ShareAlike 4.0 International](LICENSE_cc-by-sa.txt), also available at .
47 |
48 | The software contained in this repository is licensed under the terms of the [GNU General Public License](LICENSE_GPL.txt), also available at .
49 |
50 |
51 |
52 | ### Open Source shout-out
53 |
54 | All circuit diagrams were designed with Kicad/eeschema.
55 |
56 | All images were exported from Kicad/eeschema and edited (graphic lines and arrows added) using GIMP (and the ArrowCurved plugin).
57 |
58 | The physical circuit board was designed with Kicad/pcbnew.
59 |
60 | The example software implementation source code was written using GNU Emacs and compiled with the GCC ARM compiler.
61 |
62 | This README.md was written using GNU Emacs and tested with Discount/Markdown.
63 |
64 |
65 |
66 | Background material
67 | -------------------
68 |
69 | This section contains background explanations of microcontroller (MCU) switch interfacing, switch matrix encoding, and charlieplexing.
70 |
71 | Those familiar with MCU switch interfacing should skip ahead to [MxN switch matrix encoding](#mxn_switch_matrix_encoding)
72 |
73 | Those familiar with charlieplexing should skip ahead to [Markoplexing](#markoplexing)
74 |
75 | Those understandably annoyed at being told what to skip should skip this entire repository. Note, however, that this is the last of the "skip" suggestions.
76 |
77 |
78 | ### MCU switch interfacing
79 |
80 | Physical switches are normally interfaced (connected) to microcontrollers and similar ICs using one of two slightly different methods.
81 |
82 | Since unconnected MCU input ports are subject to random electrical noise which can cause false readings, switches are usually connected in such a way that their associated input port is always in a known state regardless of whether the switch is open or closed.
83 |
84 | The two methods are:
85 |
86 | 1. Logic *low==true*: The input port is connected to the positive voltage supply through a "pull up" resistor. The switch is also connected to the port, and when closed shorts it to ground. (The resistor prevents excess current flow.) When the switch is open the input port reads as *high*, and when closed *low*.
87 |
88 | 2. Logic *high==true*: The input port is connected to the ground through a "pull down" resistor. The switch is also connected to the port, and when closed shorts it to the positive voltage supply. (Again the resistor prevents excess current flow.) When the switch is open the input port reads as *low*, and when closed *high*.
89 |
90 | Note that in both cases the resistors may be external, or internal to the MCU and enabled or disabled via software.
91 |
92 | The following figure illustrates a variation of these methods, in which instead of the switch being connected to power or ground it is connected to a separate MCU output port which provides the appropriate "switch open" voltage level. If that voltage is output, the switch input behaves as described above. If it is not -- the output port is disabled to a high impedance state -- the switch has no effect; however the input port remains in its known state via the pull-up/-down resistor.
93 |
94 | This method is not necessary (though it is still usable) for singly-connected switches. It is important for use with the switch matrix encoding schemes described below because it allows enabling and disabling the switches.
95 |
96 | 
97 |
98 | ##### Logic==high in all examples
99 | Note that all examples in this README.md, and all code in this repository, assume high==true / pull-down resistors. The opposite could be used equally well, but would require reversing the polarity of the diodes in the circuit diagrams below.
100 |
101 |
102 | ### MxN switch matrix encoding
103 |
104 | Normally, interfacing **N** switches to a microcontroller would require **N** MCU input ports. While this is practical for small numbers of switches, it becomes unworkable as **N** becomes large.
105 |
106 | A common technique for interfacing large numbers of switches (such as a numeric keypad or particularly a PC keyboard) is to arrange **M*N** switches in an **MxN** rectangular matrix. In this way the **M*N** switches can be interfaced using only **M+N** I/O ports.
107 |
108 | Note that to get the greatest benefit from this scheme, **M** and **N** should be approximately equal, i.e. the rectangular matrix should be as square
109 | as possible. For example, 100 switches may be arranged in the following matrices:
110 |
111 | M N M*N M+N 100-(M+N) extras
112 | - --- --- --- --------- ------
113 | 1 100 100 101 -1
114 | 2 50 100 52 48
115 | 3 34 100 37 63 2
116 | 4 25 100 29 71
117 | 5 20 100 25 75
118 | 6 18 100 24 76 8
119 | 7 15 100 22 78 5
120 | 8 13 100 21 79 4
121 | 9 12 100 21 79 8
122 | 10 10 100 20 80
123 |
124 | The best benefit (80 fewer I/O ports) is achieved with the 10x10 matrix.
125 |
126 | Note also that the topological connections of the matrix need not match the physical layout/geometry of the switches.
127 |
128 | The following figure illustrates a 3x4 **MxN** matrix encoding for the common 12-key numeric keypad.
129 |
130 | 
131 |
132 |
133 | ### Scanning
134 |
135 | Matrix-encoded switches are read by MCU software using a *scanning* technique. The rows of the matrix are connected to MCU output ports, and the columns to input ports. (Note that the distinction between "rows" and "columns" is arbitrary -- either dimension may be assigned arbitrarily as long as the assignments are consistent.)
136 |
137 | Scanning proceeds as follows:
138 |
139 | 1. All row outputs are initialized to inactive, high-impedance state.
140 | 2. Each row in turn is "energized" (set to high or low level, depending on the "logic true" level, pull-up/-down convention chosen; see [above](#all_examples_logic_high_true))
141 | 3. The states of the input ports are read. By correlating which row is energized with which input ports are "true", the subset of switches which are closed is uniquely known.
142 | 4. The row output is de-energized.
143 | 5. Steps 2 through 4 are repeated until all rows have been energized, and all switch closures detected.
144 |
145 | One step of the scanning process is illustrated in the following figure. At the time shown, Row 2 is energized, which in combination with switch r2c3 ("row 2, column 3") being closed causes the Column 3 input port to read "true" while Columns 1, 2, and 4 read "false". Note that the closed states of switches r1c2, r3c1, and r3c4 have no effect as only Row 2 is energized. The red arrow line shows current flow from the Row 2 output to the Column 3 input.
146 |
147 | 
148 |
149 |
150 | Multiple closed switches in the same row are read similarly. In example below, Row 3 is energized and the closed switches r3c1 and r3c4 are simultaneously read on inputs Column 1 and Column 4
151 |
152 | 
153 |
154 |
155 | ### The "ghost" switch problem
156 |
157 | Unfortunately, matrix switch encoding has a significant flaw. If certain combinations of switches are closed simultaneously, the technique will spuriously read one or more open switches as closed.
158 |
159 | The following figure illustrates the problem. Switches r1c3, r1c4, and r2c4 are closed. When Row 1 is energized (not illustrated), switches r1c3 and r1c4 are correctly read on input ports Column 3 and Column 4.
160 |
161 | However, when Row 2 is energized as shown, current flows through switch r2c4 and is correctly detected at input port Column 4. But the current also flows "backwards" through switch r1c4 to row1, and from there through switch r1c3 to the Column 3 input port, as shown by the magenta arrow line.
162 |
163 | This causes the scanning software algorithm to falsely read switch r2c3 as closed when in fact it is not. This is colloquially known as a "ghost" switch closure because it as if some supernatural entity has closed the switch.
164 |
165 | 
166 |
167 |
168 | ### The diode fix for ghosting
169 |
170 | Fortunately, there is a simple fix for the "ghost" switch problem, although it requires additional hardware. By adding a diode in series with each switch, the "backward" current flow is stopped. The figure below is identical to the one above except for the additional diodes. The magenta arrow line shows current being prevented from flowing through switch r1c4 to Row 1, and switch r2c3 is not read as a ghost closure.
171 |
172 | 
173 |
174 |
175 |
176 | ### Charlieplexing
177 |
178 | "Charlieplexing" is a very clever scheme which allows interfacing **N*(N-1)** switches using only **N** I/O lines -- typically far fewer than required by **MxN** matrix encoding. Note that the "I/O lines" distinction is important: In charlieplexing, ports must be dynamically switchable, sometimes being configured as inputs and at other times as outputs.
179 |
180 | A charlieplexed circuit for 12 switches interfaced with 4 lines (`4*(4-3)==12`) is shown below. The circuit is best understood as having each of the I/O ports -- when temporarily configured as an output -- connected to 3 switches. The other sides of the switches are connected to one of the remaining 3 I/O ports, each of which is simultaneously/temporarily configured as an input.
181 |
182 | 
183 |
184 |
185 | Scanning is similar to the MxN matrix algorithm:
186 |
187 | 1. All ports are configured as inputs
188 | 2. Each port in turn configured as an output and "energized" (set to high or low level, depending on the "logic true" level, pull-up/-down convention chosen; see [above](#all_examples_logic_high_true)).
189 | 3. The remaining ports are read. By correlating which port is the energized output with which input ports are "true", the subset of switches which are closed is uniquely known.
190 | 4. The output port is de-energized and returned to "input" configuration.
191 | 5. Steps 2 through 4 are repeated until all ports have been output-energized, and all switch closures detected.
192 |
193 | The following figure shows scanning with port C configured as an output, and port D reading the switch 6 closure as an input
194 |
195 | 
196 |
197 |
198 | Similar to MxN matrices, multiple charlieplexed switches can be closed simultaneously and (sometimes! -- see below) correctly read. In the following figure, switches 4 and 6 are closed and read correctly.
199 |
200 |
201 | 
202 |
203 |
204 | However, charlieplexing also suffers from ghost switch problems. The following figure shows current flowing from output port C, through switch 6, and being correctly detected at input port D. But since the switch 6 closure energizes the port D line, current flows "backwards" through closed switch 9, and then through switch 7 to input port A, just as it does when port D is intentionally energized and reading switch 1 of the 1-through-3 group. There is no way for port A to "know" the difference between this and the case where switch 4 is closed together with switch 6 as illustrated [above](#charlieplex_4_and_6), and switch 4 is read as a "ghost" closure.
205 |
206 | 
207 |
208 |
209 | As with MxN matrices, diodes can be added to prevent the backward flow and ghost switch misreads. The figure below illustrates this, with the flow through switch 9 being prevented by its associated diode, and the switch-7-read-as-ghost-switch-4 error avoided.
210 |
211 | 
212 |
213 |
214 | But a significant problem remains. The following figure illustrates a different kind of ghosting. Again, current flows correctly from output port C, through switch 6, and is detected at input port D. Also again, this energizes the port D line and current flows through switch 1 to input port A causing switch 4 to be falsely read as a ghost closure.
215 |
216 | 
217 |
218 |
219 | But as opposed to the situation with MxN matrices, where diodes fixed all ghosting problems, in charlieplexing they only prevent some "ghosts". In the above example (among others), the incorrect current flow through switch 1 is in the "correct" direction, just as it would be when port D is energized to read switches 1 through 3. The following shows how the current passes through the diode and is still incorrectly read at port A.
220 |
221 |
222 | 
223 |
224 |
225 | This is the fatal flaw of charlieplexing. Note that it is "fatal" only if multiple switch closures need to be detected correctly and ghosts ignored. If the physical hardware only allows one switch closure at a time, or the system is allowed to reject cases when multiple switches are read (or mis-read) as closed, the flaw is unimportant.
226 |
227 | But if any and all combinations of multiple switches must be detected correctly (without ghosts), charlieplexing -- and its benefit of reduced I/O port count -- cannot be used. There is no way around the ghosting problem.
228 |
229 | *Or is there?*
230 |
231 |
232 |
233 | Markoplexing
234 | ----------------------------------------
235 |
236 | "Markoplexing" (see ["Claimer"](#claimer), above) is a very simple idea which distinguishes between real and ghost charlieplex switch closures. It is a software-only technique which requires no changes to the (diode-enhanced) charlieplex circuit topologies. This is achieved as follows ...
237 |
238 | Observe that the two current flows, one correct and one "ghost", in the final circuit diagram [above](#charlieplex_fatal). The correct one goes through diode 6 (and switch 6). The ghost current flows goes diode 6 ... *and* diode 1.
239 |
240 | The correct input port sees the output port's voltage minus one diode voltage drop. The incorrect/ghost port sees **two** diode drops.
241 |
242 | *A-ha!* What if, rather than configuring and reading the ports as digital inputs (true/false, one/zero) they are configured and read as *analog* inputs (voltage)? The difference between the voltage levels in the correct and ghost cases can then be detected, and the latter rejected.
243 |
244 | *Charlieplex ghosting fixed!*
245 |
246 | Note that this technique has several requirements:
247 |
248 | * A microcontroller with either analog-to-digital (ADC) or analog comparator inputs
249 | * ... which can be dynamically switched between analog input and digital output modes.
250 | * Correct configuration of the analog voltage threshold between one vs more than one diode voltage drop
251 | * ... diode voltage drops which, due to the very low currents passing through the high input impedance of the input ports, are *not* the canonically-spec'd value (typically 0.7V).
252 |
253 | Note also that, as tempting as it may seem, it is probably impossible to discriminate between the one and multiple diode voltage drops using a digital input port. Digital input ports always have thresholds for the detection of high and low logic levels with an "undefined" voltage zone in between.
254 |
255 | These levels are typically `0.3Vdd`, below which a logic 0 is read, and `0.7Vdd` above which is logic 1. There is no mathematically possible forward diode voltage drop `Vf` which simultaneously satisfies the two required inequalities:
256 |
257 | Vdd - Vf > 0.7Vdd
258 | Vdd - 2Vf < 0.3Vdd
259 |
260 | Despite this, the required analog threshold can be adjusted by appropriate choice of diode, including Schottky for low Vf or light-emitting (LED) for high Vf.
261 |
262 |
263 | ### Debouncing and EMI
264 |
265 | Switch debouncing -- ignoring the very rapid (sub-millisecond) opening and closing of switches due to their mechanical construction -- is outside the scope of this document and repository. However, it may be possible to add capacitors to the switches to increase switch closure voltage rise time. Additionally, it may be possible to "ramp up" the output port voltage by using analog instead of digital outputs, which may in turn reduce edge-induced EMI caused by scanning. Both of these techniques could be used with digital inputs, but better results might be obtained with the analog input technique, particularly if the input ports have configurable hysteresis.
266 |
267 |
268 | ### Testing
269 |
270 | The "markoplexing" technique presented here is not merely a theoretical concept -- it has been tested (and works as described) in a real-world demonstration.
271 |
272 | A 12-switch charlieplex circuit was constructed and tested using the markoplex technique. All 4096 possible switch combinations were not checked; those are far too many for manual testing and I have not had the time or resources to construct a testbed which uses solenoids, relays, transistors, opto-isolators, CMOS analog switches, etc. to automate the process.
273 |
274 | However, many specifically chosen multiple-closed-switch combinations *were* tested. All exhibited ghosting as expected with charlieplexing software, and none with markoplexing. More conclusively, all 12 possible permutations of "all switches closed except for one left open" were checked -- if anything would cause ghosts those would (but with markoplexing did not).
275 |
276 |
277 |
278 | ### Example software implementation
279 |
280 |
281 | Included here is an example software implementation for the NXP LPC824 microcontroller chip. Both a charlieplexing and a markoplexing executable can be built to better compare the original and modified techniques.
282 |
283 | Also included is a primitive standalone build system for compiling the executables. Most users will probably want to extract only the basic code (contained in the [source](source) directory) for use in their own build environments.
284 |
285 | Basic constants describing I/O port (thus physical MCU pin) assignments, etc (many "etceteras") are contained [main.c](source/main.c), [markoplex.c](source/markoplex.c), and [display.c](source/display.c) source files. A differently connected LPC824 would require changing these. Of course a different MCU would require a complete rewrite of the code, which, in the interest of simplicity and clarity, is written in C and without attempts to make it generic or portable.
286 |
287 | If a 12 LED APA102 "smart" RGB strip is available it can be connected and driven by the LPC824's SPI peripheral to display the detected switch closures (actual and/or ghost). See the file [display.c](source/display.c) and the `#ifdef USE_DISPLAY` conditional compilation directive. If not, the included `markcharl.gdb` file's "dprintf" command can be used instead (or in addition).
288 |
289 | The `#ifdef SWITCHABLE_KEYPAD` configuration is for use with the [circuit](#configurable_circuit), below.
290 |
291 |
292 |
293 |
294 | Configurable circuit (matrix/charlieplex)
295 | ----------------------------------------
296 |
297 | As an extra added bonus for the first 100 users to clone or download this repository (as well as any and all others -- I have no plans to remove the circuit, I just like the sound of the marketing phrase "for the first 100") will receive, free of charge, the following circuit diagram which can be configured via jumpers into either a 3x4 matrix or a 12-key/4-port charlieplex arrangement.
298 |
299 | The three 4-position headers shown as all jumpered represent an incorrect configuration. (I didn't know how to draw headers/jumpers differently.) To use the circuit as a 3x4 matrix, connect the middle two pins (#2 and #3) of each of the three headers.
300 |
301 | To use it as for 12-key/4-port charlieplexing/markoplexing, connect the outer sets of pins (#1 to #2 and #3 to #4) on each header, and connect columns 1 through 4 to the four I/O ports. (The row 1 through 3 connections are unused in this configuration.) The switch numbers in this diagram map to the ones in the charlieplex diagrams above as:
302 |
303 | configurable charlieplex
304 | ------------ -----------
305 | Col1 D
306 | Col2 A
307 | Col3 B
308 | Col4 C
309 |
310 | r1c2 sw1 A
311 | r1c3 sw2 B
312 | r1c3 sw3 C
313 |
314 | r2c1 sw12 D
315 | r2c3 sw10 B
316 | r2c4 sw11 C
317 |
318 | r3c1 sw9 D
319 | r3c2 sw7 A
320 | r3c4 sw8 C
321 |
322 | r1c1 sw6 D
323 | r2c2 sw4 A
324 | r3c3 sw5 B
325 |
326 |
327 | This should be (somewhat) clear from tracing the circuit.
328 |
329 | Enjoy!
330 |
331 | 
332 |
--------------------------------------------------------------------------------
/images/3x4_all_open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/3x4_all_open.png
--------------------------------------------------------------------------------
/images/3x4_r2c3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/3x4_r2c3.png
--------------------------------------------------------------------------------
/images/3x4_r2c4_r1c4r1c3_noghost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/3x4_r2c4_r1c4r1c3_noghost.png
--------------------------------------------------------------------------------
/images/3x4_r2c4_r1c4r1c3ghost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/3x4_r2c4_r1c4r1c3ghost.png
--------------------------------------------------------------------------------
/images/3x4_r3c14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/3x4_r3c14.png
--------------------------------------------------------------------------------
/images/plex_all_open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/plex_all_open.png
--------------------------------------------------------------------------------
/images/plex_c6_97a_ghost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/plex_c6_97a_ghost.png
--------------------------------------------------------------------------------
/images/plex_c6_9_diodes_no_ghost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/plex_c6_9_diodes_no_ghost.png
--------------------------------------------------------------------------------
/images/plex_c6d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/plex_c6d.png
--------------------------------------------------------------------------------
/images/plex_c6d_1a_diodes_ghost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/plex_c6d_1a_diodes_ghost.png
--------------------------------------------------------------------------------
/images/plex_c6d_1a_ghost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/plex_c6d_1a_ghost.png
--------------------------------------------------------------------------------
/images/plex_c_6d4a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/plex_c_6d4a.png
--------------------------------------------------------------------------------
/images/pullup_pulldown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/pullup_pulldown.png
--------------------------------------------------------------------------------
/images/switchable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thanks4opensource/markoplexing/20023355cc361346576dad5e514eb6139a02cd93/images/switchable.png
--------------------------------------------------------------------------------
/include/arm/core_cm0plus.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************//**
2 | * @file core_cm0plus.h
3 | * @brief CMSIS Cortex-M0+ Core Peripheral Access Layer Header File
4 | * @version V4.30
5 | * @date 20. October 2015
6 | ******************************************************************************/
7 | /* Copyright (c) 2009 - 2015 ARM LIMITED
8 |
9 | All rights reserved.
10 | Redistribution and use in source and binary forms, with or without
11 | modification, are permitted provided that the following conditions are met:
12 | - Redistributions of source code must retain the above copyright
13 | notice, this list of conditions and the following disclaimer.
14 | - Redistributions in binary form must reproduce the above copyright
15 | notice, this list of conditions and the following disclaimer in the
16 | documentation and/or other materials provided with the distribution.
17 | - Neither the name of ARM nor the names of its contributors may be used
18 | to endorse or promote products derived from this software without
19 | specific prior written permission.
20 | *
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | POSSIBILITY OF SUCH DAMAGE.
32 | ---------------------------------------------------------------------------*/
33 |
34 |
35 | #if defined ( __ICCARM__ )
36 | #pragma system_include /* treat file as system include file for MISRA check */
37 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
38 | #pragma clang system_header /* treat file as system include file */
39 | #endif
40 |
41 | #ifndef __CORE_CM0PLUS_H_GENERIC
42 | #define __CORE_CM0PLUS_H_GENERIC
43 |
44 | #include
45 |
46 | #ifdef __cplusplus
47 | extern "C" {
48 | #endif
49 |
50 | /**
51 | \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions
52 | CMSIS violates the following MISRA-C:2004 rules:
53 |
54 | \li Required Rule 8.5, object/function definition in header file.
55 | Function definitions in header files are used to allow 'inlining'.
56 |
57 | \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
58 | Unions are used for effective representation of core registers.
59 |
60 | \li Advisory Rule 19.7, Function-like macro defined.
61 | Function-like macros are used to allow more efficient code.
62 | */
63 |
64 |
65 | /*******************************************************************************
66 | * CMSIS definitions
67 | ******************************************************************************/
68 | /**
69 | \ingroup Cortex-M0+
70 | @{
71 | */
72 |
73 | /* CMSIS CM0+ definitions */
74 | #define __CM0PLUS_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */
75 | #define __CM0PLUS_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */
76 | #define __CM0PLUS_CMSIS_VERSION ((__CM0PLUS_CMSIS_VERSION_MAIN << 16U) | \
77 | __CM0PLUS_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */
78 |
79 | #define __CORTEX_M (0x00U) /*!< Cortex-M Core */
80 |
81 |
82 | #if defined ( __CC_ARM )
83 | #define __ASM __asm /*!< asm keyword for ARM Compiler */
84 | #define __INLINE __inline /*!< inline keyword for ARM Compiler */
85 | #define __STATIC_INLINE static __inline
86 |
87 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
88 | #define __ASM __asm /*!< asm keyword for ARM Compiler */
89 | #define __INLINE __inline /*!< inline keyword for ARM Compiler */
90 | #define __STATIC_INLINE static __inline
91 |
92 | #elif defined ( __GNUC__ )
93 | #define __ASM __asm /*!< asm keyword for GNU Compiler */
94 | #define __INLINE inline /*!< inline keyword for GNU Compiler */
95 | #define __STATIC_INLINE static inline
96 |
97 | #elif defined ( __ICCARM__ )
98 | #define __ASM __asm /*!< asm keyword for IAR Compiler */
99 | #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */
100 | #define __STATIC_INLINE static inline
101 |
102 | #elif defined ( __TMS470__ )
103 | #define __ASM __asm /*!< asm keyword for TI CCS Compiler */
104 | #define __STATIC_INLINE static inline
105 |
106 | #elif defined ( __TASKING__ )
107 | #define __ASM __asm /*!< asm keyword for TASKING Compiler */
108 | #define __INLINE inline /*!< inline keyword for TASKING Compiler */
109 | #define __STATIC_INLINE static inline
110 |
111 | #elif defined ( __CSMC__ )
112 | #define __packed
113 | #define __ASM _asm /*!< asm keyword for COSMIC Compiler */
114 | #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */
115 | #define __STATIC_INLINE static inline
116 |
117 | #else
118 | #error Unknown compiler
119 | #endif
120 |
121 | /** __FPU_USED indicates whether an FPU is used or not.
122 | This core does not support an FPU at all
123 | */
124 | #define __FPU_USED 0U
125 |
126 | #if defined ( __CC_ARM )
127 | #if defined __TARGET_FPU_VFP
128 | #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
129 | #endif
130 |
131 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
132 | #if defined __ARM_PCS_VFP
133 | #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
134 | #endif
135 |
136 | #elif defined ( __GNUC__ )
137 | #if defined (__VFP_FP__) && !defined(__SOFTFP__)
138 | #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
139 | #endif
140 |
141 | #elif defined ( __ICCARM__ )
142 | #if defined __ARMVFP__
143 | #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
144 | #endif
145 |
146 | #elif defined ( __TMS470__ )
147 | #if defined __TI_VFP_SUPPORT__
148 | #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
149 | #endif
150 |
151 | #elif defined ( __TASKING__ )
152 | #if defined __FPU_VFP__
153 | #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
154 | #endif
155 |
156 | #elif defined ( __CSMC__ )
157 | #if ( __CSMC__ & 0x400U)
158 | #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
159 | #endif
160 |
161 | #endif
162 |
163 | #include "core_cmInstr.h" /* Core Instruction Access */
164 | #include "core_cmFunc.h" /* Core Function Access */
165 |
166 | #ifdef __cplusplus
167 | }
168 | #endif
169 |
170 | #endif /* __CORE_CM0PLUS_H_GENERIC */
171 |
172 | #ifndef __CMSIS_GENERIC
173 |
174 | #ifndef __CORE_CM0PLUS_H_DEPENDANT
175 | #define __CORE_CM0PLUS_H_DEPENDANT
176 |
177 | #ifdef __cplusplus
178 | extern "C" {
179 | #endif
180 |
181 | /* check device defines and use defaults */
182 | #if defined __CHECK_DEVICE_DEFINES
183 | #ifndef __CM0PLUS_REV
184 | #define __CM0PLUS_REV 0x0000U
185 | #warning "__CM0PLUS_REV not defined in device header file; using default!"
186 | #endif
187 |
188 | #ifndef __MPU_PRESENT
189 | #define __MPU_PRESENT 0U
190 | #warning "__MPU_PRESENT not defined in device header file; using default!"
191 | #endif
192 |
193 | #ifndef __VTOR_PRESENT
194 | #define __VTOR_PRESENT 0U
195 | #warning "__VTOR_PRESENT not defined in device header file; using default!"
196 | #endif
197 |
198 | #ifndef __NVIC_PRIO_BITS
199 | #define __NVIC_PRIO_BITS 2U
200 | #warning "__NVIC_PRIO_BITS not defined in device header file; using default!"
201 | #endif
202 |
203 | #ifndef __Vendor_SysTickConfig
204 | #define __Vendor_SysTickConfig 0U
205 | #warning "__Vendor_SysTickConfig not defined in device header file; using default!"
206 | #endif
207 | #endif
208 |
209 | /* IO definitions (access restrictions to peripheral registers) */
210 | /**
211 | \defgroup CMSIS_glob_defs CMSIS Global Defines
212 |
213 | IO Type Qualifiers are used
214 | \li to specify the access to peripheral variables.
215 | \li for automatic generation of peripheral register debug information.
216 | */
217 | #ifdef __cplusplus
218 | #define __I volatile /*!< Defines 'read only' permissions */
219 | #else
220 | #define __I volatile const /*!< Defines 'read only' permissions */
221 | #endif
222 | #define __O volatile /*!< Defines 'write only' permissions */
223 | #define __IO volatile /*!< Defines 'read / write' permissions */
224 |
225 | /* following defines should be used for structure members */
226 | #define __IM volatile const /*! Defines 'read only' structure member permissions */
227 | #define __OM volatile /*! Defines 'write only' structure member permissions */
228 | #define __IOM volatile /*! Defines 'read / write' structure member permissions */
229 |
230 | /*@} end of group Cortex-M0+ */
231 |
232 |
233 |
234 | /*******************************************************************************
235 | * Register Abstraction
236 | Core Register contain:
237 | - Core Register
238 | - Core NVIC Register
239 | - Core SCB Register
240 | - Core SysTick Register
241 | - Core MPU Register
242 | ******************************************************************************/
243 | /**
244 | \defgroup CMSIS_core_register Defines and Type Definitions
245 | \brief Type definitions and defines for Cortex-M processor based devices.
246 | */
247 |
248 | /**
249 | \ingroup CMSIS_core_register
250 | \defgroup CMSIS_CORE Status and Control Registers
251 | \brief Core Register type definitions.
252 | @{
253 | */
254 |
255 | /**
256 | \brief Union type to access the Application Program Status Register (APSR).
257 | */
258 | typedef union
259 | {
260 | struct
261 | {
262 | uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */
263 | uint32_t V:1; /*!< bit: 28 Overflow condition code flag */
264 | uint32_t C:1; /*!< bit: 29 Carry condition code flag */
265 | uint32_t Z:1; /*!< bit: 30 Zero condition code flag */
266 | uint32_t N:1; /*!< bit: 31 Negative condition code flag */
267 | } b; /*!< Structure used for bit access */
268 | uint32_t w; /*!< Type used for word access */
269 | } APSR_Type;
270 |
271 | /* APSR Register Definitions */
272 | #define APSR_N_Pos 31U /*!< APSR: N Position */
273 | #define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */
274 |
275 | #define APSR_Z_Pos 30U /*!< APSR: Z Position */
276 | #define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */
277 |
278 | #define APSR_C_Pos 29U /*!< APSR: C Position */
279 | #define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */
280 |
281 | #define APSR_V_Pos 28U /*!< APSR: V Position */
282 | #define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */
283 |
284 |
285 | /**
286 | \brief Union type to access the Interrupt Program Status Register (IPSR).
287 | */
288 | typedef union
289 | {
290 | struct
291 | {
292 | uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */
293 | uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */
294 | } b; /*!< Structure used for bit access */
295 | uint32_t w; /*!< Type used for word access */
296 | } IPSR_Type;
297 |
298 | /* IPSR Register Definitions */
299 | #define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */
300 | #define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */
301 |
302 |
303 | /**
304 | \brief Union type to access the Special-Purpose Program Status Registers (xPSR).
305 | */
306 | typedef union
307 | {
308 | struct
309 | {
310 | uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */
311 | uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */
312 | uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */
313 | uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */
314 | uint32_t V:1; /*!< bit: 28 Overflow condition code flag */
315 | uint32_t C:1; /*!< bit: 29 Carry condition code flag */
316 | uint32_t Z:1; /*!< bit: 30 Zero condition code flag */
317 | uint32_t N:1; /*!< bit: 31 Negative condition code flag */
318 | } b; /*!< Structure used for bit access */
319 | uint32_t w; /*!< Type used for word access */
320 | } xPSR_Type;
321 |
322 | /* xPSR Register Definitions */
323 | #define xPSR_N_Pos 31U /*!< xPSR: N Position */
324 | #define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */
325 |
326 | #define xPSR_Z_Pos 30U /*!< xPSR: Z Position */
327 | #define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */
328 |
329 | #define xPSR_C_Pos 29U /*!< xPSR: C Position */
330 | #define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */
331 |
332 | #define xPSR_V_Pos 28U /*!< xPSR: V Position */
333 | #define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */
334 |
335 | #define xPSR_T_Pos 24U /*!< xPSR: T Position */
336 | #define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */
337 |
338 | #define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */
339 | #define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */
340 |
341 |
342 | /**
343 | \brief Union type to access the Control Registers (CONTROL).
344 | */
345 | typedef union
346 | {
347 | struct
348 | {
349 | uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */
350 | uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */
351 | uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */
352 | } b; /*!< Structure used for bit access */
353 | uint32_t w; /*!< Type used for word access */
354 | } CONTROL_Type;
355 |
356 | /* CONTROL Register Definitions */
357 | #define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */
358 | #define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */
359 |
360 | #define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */
361 | #define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */
362 |
363 | /*@} end of group CMSIS_CORE */
364 |
365 |
366 | /**
367 | \ingroup CMSIS_core_register
368 | \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC)
369 | \brief Type definitions for the NVIC Registers
370 | @{
371 | */
372 |
373 | /**
374 | \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC).
375 | */
376 | typedef struct
377 | {
378 | __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
379 | uint32_t RESERVED0[31U];
380 | __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
381 | uint32_t RSERVED1[31U];
382 | __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
383 | uint32_t RESERVED2[31U];
384 | __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
385 | uint32_t RESERVED3[31U];
386 | uint32_t RESERVED4[64U];
387 | __IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */
388 | } NVIC_Type;
389 |
390 | /*@} end of group CMSIS_NVIC */
391 |
392 |
393 | /**
394 | \ingroup CMSIS_core_register
395 | \defgroup CMSIS_SCB System Control Block (SCB)
396 | \brief Type definitions for the System Control Block Registers
397 | @{
398 | */
399 |
400 | /**
401 | \brief Structure type to access the System Control Block (SCB).
402 | */
403 | typedef struct
404 | {
405 | __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
406 | __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
407 | #if (__VTOR_PRESENT == 1U)
408 | __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */
409 | #else
410 | uint32_t RESERVED0;
411 | #endif
412 | __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
413 | __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
414 | __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
415 | uint32_t RESERVED1;
416 | __IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */
417 | __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
418 | } SCB_Type;
419 |
420 | /* SCB CPUID Register Definitions */
421 | #define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */
422 | #define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */
423 |
424 | #define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */
425 | #define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */
426 |
427 | #define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */
428 | #define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */
429 |
430 | #define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */
431 | #define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */
432 |
433 | #define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */
434 | #define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */
435 |
436 | /* SCB Interrupt Control State Register Definitions */
437 | #define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */
438 | #define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */
439 |
440 | #define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */
441 | #define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */
442 |
443 | #define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */
444 | #define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */
445 |
446 | #define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */
447 | #define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */
448 |
449 | #define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */
450 | #define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */
451 |
452 | #define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */
453 | #define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */
454 |
455 | #define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */
456 | #define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */
457 |
458 | #define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */
459 | #define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */
460 |
461 | #define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */
462 | #define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */
463 |
464 | #if (__VTOR_PRESENT == 1U)
465 | /* SCB Interrupt Control State Register Definitions */
466 | #define SCB_VTOR_TBLOFF_Pos 8U /*!< SCB VTOR: TBLOFF Position */
467 | #define SCB_VTOR_TBLOFF_Msk (0xFFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */
468 | #endif
469 |
470 | /* SCB Application Interrupt and Reset Control Register Definitions */
471 | #define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */
472 | #define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */
473 |
474 | #define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */
475 | #define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */
476 |
477 | #define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */
478 | #define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */
479 |
480 | #define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */
481 | #define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */
482 |
483 | #define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */
484 | #define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */
485 |
486 | /* SCB System Control Register Definitions */
487 | #define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */
488 | #define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */
489 |
490 | #define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */
491 | #define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */
492 |
493 | #define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */
494 | #define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */
495 |
496 | /* SCB Configuration Control Register Definitions */
497 | #define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */
498 | #define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */
499 |
500 | #define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */
501 | #define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */
502 |
503 | /* SCB System Handler Control and State Register Definitions */
504 | #define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */
505 | #define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */
506 |
507 | /*@} end of group CMSIS_SCB */
508 |
509 |
510 | /**
511 | \ingroup CMSIS_core_register
512 | \defgroup CMSIS_SysTick System Tick Timer (SysTick)
513 | \brief Type definitions for the System Timer Registers.
514 | @{
515 | */
516 |
517 | /**
518 | \brief Structure type to access the System Timer (SysTick).
519 | */
520 | typedef struct
521 | {
522 | __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
523 | __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
524 | __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
525 | __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
526 | } SysTick_Type;
527 |
528 | /* SysTick Control / Status Register Definitions */
529 | #define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */
530 | #define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
531 |
532 | #define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */
533 | #define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
534 |
535 | #define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */
536 | #define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
537 |
538 | #define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */
539 | #define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */
540 |
541 | /* SysTick Reload Register Definitions */
542 | #define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */
543 | #define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */
544 |
545 | /* SysTick Current Register Definitions */
546 | #define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */
547 | #define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */
548 |
549 | /* SysTick Calibration Register Definitions */
550 | #define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */
551 | #define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
552 |
553 | #define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */
554 | #define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
555 |
556 | #define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */
557 | #define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */
558 |
559 | /*@} end of group CMSIS_SysTick */
560 |
561 | #if (__MPU_PRESENT == 1U)
562 | /**
563 | \ingroup CMSIS_core_register
564 | \defgroup CMSIS_MPU Memory Protection Unit (MPU)
565 | \brief Type definitions for the Memory Protection Unit (MPU)
566 | @{
567 | */
568 |
569 | /**
570 | \brief Structure type to access the Memory Protection Unit (MPU).
571 | */
572 | typedef struct
573 | {
574 | __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */
575 | __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */
576 | __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */
577 | __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */
578 | __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */
579 | } MPU_Type;
580 |
581 | /* MPU Type Register Definitions */
582 | #define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */
583 | #define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */
584 |
585 | #define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */
586 | #define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */
587 |
588 | #define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */
589 | #define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */
590 |
591 | /* MPU Control Register Definitions */
592 | #define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */
593 | #define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */
594 |
595 | #define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */
596 | #define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */
597 |
598 | #define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */
599 | #define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */
600 |
601 | /* MPU Region Number Register Definitions */
602 | #define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */
603 | #define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */
604 |
605 | /* MPU Region Base Address Register Definitions */
606 | #define MPU_RBAR_ADDR_Pos 8U /*!< MPU RBAR: ADDR Position */
607 | #define MPU_RBAR_ADDR_Msk (0xFFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */
608 |
609 | #define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */
610 | #define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */
611 |
612 | #define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */
613 | #define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */
614 |
615 | /* MPU Region Attribute and Size Register Definitions */
616 | #define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */
617 | #define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */
618 |
619 | #define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */
620 | #define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */
621 |
622 | #define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */
623 | #define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */
624 |
625 | #define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */
626 | #define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */
627 |
628 | #define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */
629 | #define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */
630 |
631 | #define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */
632 | #define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */
633 |
634 | #define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */
635 | #define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */
636 |
637 | #define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */
638 | #define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */
639 |
640 | #define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */
641 | #define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */
642 |
643 | #define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */
644 | #define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */
645 |
646 | /*@} end of group CMSIS_MPU */
647 | #endif
648 |
649 |
650 | /**
651 | \ingroup CMSIS_core_register
652 | \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug)
653 | \brief Cortex-M0+ Core Debug Registers (DCB registers, SHCSR, and DFSR) are only accessible over DAP and not via processor.
654 | Therefore they are not covered by the Cortex-M0+ header file.
655 | @{
656 | */
657 | /*@} end of group CMSIS_CoreDebug */
658 |
659 |
660 | /**
661 | \ingroup CMSIS_core_register
662 | \defgroup CMSIS_core_bitfield Core register bit field macros
663 | \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk).
664 | @{
665 | */
666 |
667 | /**
668 | \brief Mask and shift a bit field value for use in a register bit range.
669 | \param[in] field Name of the register bit field.
670 | \param[in] value Value of the bit field.
671 | \return Masked and shifted value.
672 | */
673 | #define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk)
674 |
675 | /**
676 | \brief Mask and shift a register value to extract a bit filed value.
677 | \param[in] field Name of the register bit field.
678 | \param[in] value Value of register.
679 | \return Masked and shifted bit field value.
680 | */
681 | #define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos)
682 |
683 | /*@} end of group CMSIS_core_bitfield */
684 |
685 |
686 | /**
687 | \ingroup CMSIS_core_register
688 | \defgroup CMSIS_core_base Core Definitions
689 | \brief Definitions for base addresses, unions, and structures.
690 | @{
691 | */
692 |
693 | /* Memory mapping of Cortex-M0+ Hardware */
694 | #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
695 | #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
696 | #define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */
697 | #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
698 |
699 | #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
700 | #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
701 | #define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */
702 |
703 | #if (__MPU_PRESENT == 1U)
704 | #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */
705 | #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */
706 | #endif
707 |
708 | /*@} */
709 |
710 |
711 |
712 | /*******************************************************************************
713 | * Hardware Abstraction Layer
714 | Core Function Interface contains:
715 | - Core NVIC Functions
716 | - Core SysTick Functions
717 | - Core Register Access Functions
718 | ******************************************************************************/
719 | /**
720 | \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference
721 | */
722 |
723 |
724 |
725 | /* ########################## NVIC functions #################################### */
726 | /**
727 | \ingroup CMSIS_Core_FunctionInterface
728 | \defgroup CMSIS_Core_NVICFunctions NVIC Functions
729 | \brief Functions that manage interrupts and exceptions via the NVIC.
730 | @{
731 | */
732 |
733 | /* Interrupt Priorities are WORD accessible only under ARMv6M */
734 | /* The following MACROS handle generation of the register offset and byte masks */
735 | #define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL)
736 | #define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) )
737 | #define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) )
738 |
739 |
740 | /**
741 | \brief Enable External Interrupt
742 | \details Enables a device-specific interrupt in the NVIC interrupt controller.
743 | \param [in] IRQn External interrupt number. Value cannot be negative.
744 | */
745 | __STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
746 | {
747 | NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
748 | }
749 |
750 |
751 | /**
752 | \brief Disable External Interrupt
753 | \details Disables a device-specific interrupt in the NVIC interrupt controller.
754 | \param [in] IRQn External interrupt number. Value cannot be negative.
755 | */
756 | __STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
757 | {
758 | NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
759 | }
760 |
761 |
762 | /**
763 | \brief Get Pending Interrupt
764 | \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt.
765 | \param [in] IRQn Interrupt number.
766 | \return 0 Interrupt status is not pending.
767 | \return 1 Interrupt status is pending.
768 | */
769 | __STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
770 | {
771 | return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
772 | }
773 |
774 |
775 | /**
776 | \brief Set Pending Interrupt
777 | \details Sets the pending bit of an external interrupt.
778 | \param [in] IRQn Interrupt number. Value cannot be negative.
779 | */
780 | __STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
781 | {
782 | NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
783 | }
784 |
785 |
786 | /**
787 | \brief Clear Pending Interrupt
788 | \details Clears the pending bit of an external interrupt.
789 | \param [in] IRQn External interrupt number. Value cannot be negative.
790 | */
791 | __STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
792 | {
793 | NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
794 | }
795 |
796 |
797 | /**
798 | \brief Set Interrupt Priority
799 | \details Sets the priority of an interrupt.
800 | \note The priority cannot be set for every core interrupt.
801 | \param [in] IRQn Interrupt number.
802 | \param [in] priority Priority to set.
803 | */
804 | __STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
805 | {
806 | if ((int32_t)(IRQn) < 0)
807 | {
808 | SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
809 | (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
810 | }
811 | else
812 | {
813 | NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
814 | (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
815 | }
816 | }
817 |
818 |
819 | /**
820 | \brief Get Interrupt Priority
821 | \details Reads the priority of an interrupt.
822 | The interrupt number can be positive to specify an external (device specific) interrupt,
823 | or negative to specify an internal (core) interrupt.
824 | \param [in] IRQn Interrupt number.
825 | \return Interrupt Priority.
826 | Value is aligned automatically to the implemented priority bits of the microcontroller.
827 | */
828 | __STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)
829 | {
830 |
831 | if ((int32_t)(IRQn) < 0)
832 | {
833 | return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS)));
834 | }
835 | else
836 | {
837 | return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS)));
838 | }
839 | }
840 |
841 |
842 | /**
843 | \brief System Reset
844 | \details Initiates a system reset request to reset the MCU.
845 | */
846 | __STATIC_INLINE void NVIC_SystemReset(void)
847 | {
848 | __DSB(); /* Ensure all outstanding memory accesses included
849 | buffered write are completed before reset */
850 | SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
851 | SCB_AIRCR_SYSRESETREQ_Msk);
852 | __DSB(); /* Ensure completion of memory access */
853 |
854 | for(;;) /* wait until reset */
855 | {
856 | __NOP();
857 | }
858 | }
859 |
860 | /*@} end of CMSIS_Core_NVICFunctions */
861 |
862 |
863 |
864 | /* ################################## SysTick function ############################################ */
865 | /**
866 | \ingroup CMSIS_Core_FunctionInterface
867 | \defgroup CMSIS_Core_SysTickFunctions SysTick Functions
868 | \brief Functions that configure the System.
869 | @{
870 | */
871 |
872 | #if (__Vendor_SysTickConfig == 0U)
873 |
874 | /**
875 | \brief System Tick Configuration
876 | \details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
877 | Counter is in free running mode to generate periodic interrupts.
878 | \param [in] ticks Number of ticks between two interrupts.
879 | \return 0 Function succeeded.
880 | \return 1 Function failed.
881 | \note When the variable __Vendor_SysTickConfig is set to 1, then the
882 | function SysTick_Config is not included. In this case, the file device.h
883 | must contain a vendor-specific implementation of this function.
884 | */
885 | __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
886 | {
887 | if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
888 | {
889 | return (1UL); /* Reload value impossible */
890 | }
891 |
892 | SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
893 | NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
894 | SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
895 | SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
896 | SysTick_CTRL_TICKINT_Msk |
897 | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
898 | return (0UL); /* Function successful */
899 | }
900 |
901 | #endif
902 |
903 | /*@} end of CMSIS_Core_SysTickFunctions */
904 |
905 |
906 |
907 |
908 | #ifdef __cplusplus
909 | }
910 | #endif
911 |
912 | #endif /* __CORE_CM0PLUS_H_DEPENDANT */
913 |
914 | #endif /* __CMSIS_GENERIC */
915 |
--------------------------------------------------------------------------------
/include/arm/core_cmFunc.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************//**
2 | * @file core_cmFunc.h
3 | * @brief CMSIS Cortex-M Core Function Access Header File
4 | * @version V4.30
5 | * @date 20. October 2015
6 | ******************************************************************************/
7 | /* Copyright (c) 2009 - 2015 ARM LIMITED
8 |
9 | All rights reserved.
10 | Redistribution and use in source and binary forms, with or without
11 | modification, are permitted provided that the following conditions are met:
12 | - Redistributions of source code must retain the above copyright
13 | notice, this list of conditions and the following disclaimer.
14 | - Redistributions in binary form must reproduce the above copyright
15 | notice, this list of conditions and the following disclaimer in the
16 | documentation and/or other materials provided with the distribution.
17 | - Neither the name of ARM nor the names of its contributors may be used
18 | to endorse or promote products derived from this software without
19 | specific prior written permission.
20 | *
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | POSSIBILITY OF SUCH DAMAGE.
32 | ---------------------------------------------------------------------------*/
33 |
34 |
35 | #if defined ( __ICCARM__ )
36 | #pragma system_include /* treat file as system include file for MISRA check */
37 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
38 | #pragma clang system_header /* treat file as system include file */
39 | #endif
40 |
41 | #ifndef __CORE_CMFUNC_H
42 | #define __CORE_CMFUNC_H
43 |
44 |
45 | /* ########################### Core Function Access ########################### */
46 | /** \ingroup CMSIS_Core_FunctionInterface
47 | \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
48 | @{
49 | */
50 |
51 | /*------------------ RealView Compiler -----------------*/
52 | #if defined ( __CC_ARM )
53 | #include "cmsis_armcc.h"
54 |
55 | /*------------------ ARM Compiler V6 -------------------*/
56 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
57 | #include "cmsis_armcc_V6.h"
58 |
59 | /*------------------ GNU Compiler ----------------------*/
60 | #elif defined ( __GNUC__ )
61 | #include "cmsis_gcc.h"
62 |
63 | /*------------------ ICC Compiler ----------------------*/
64 | #elif defined ( __ICCARM__ )
65 | #include
66 |
67 | /*------------------ TI CCS Compiler -------------------*/
68 | #elif defined ( __TMS470__ )
69 | #include
70 |
71 | /*------------------ TASKING Compiler ------------------*/
72 | #elif defined ( __TASKING__ )
73 | /*
74 | * The CMSIS functions have been implemented as intrinsics in the compiler.
75 | * Please use "carm -?i" to get an up to date list of all intrinsics,
76 | * Including the CMSIS ones.
77 | */
78 |
79 | /*------------------ COSMIC Compiler -------------------*/
80 | #elif defined ( __CSMC__ )
81 | #include
82 |
83 | #endif
84 |
85 | /*@} end of CMSIS_Core_RegAccFunctions */
86 |
87 | #endif /* __CORE_CMFUNC_H */
88 |
--------------------------------------------------------------------------------
/include/arm/core_cmInstr.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************//**
2 | * @file core_cmInstr.h
3 | * @brief CMSIS Cortex-M Core Instruction Access Header File
4 | * @version V4.30
5 | * @date 20. October 2015
6 | ******************************************************************************/
7 | /* Copyright (c) 2009 - 2015 ARM LIMITED
8 |
9 | All rights reserved.
10 | Redistribution and use in source and binary forms, with or without
11 | modification, are permitted provided that the following conditions are met:
12 | - Redistributions of source code must retain the above copyright
13 | notice, this list of conditions and the following disclaimer.
14 | - Redistributions in binary form must reproduce the above copyright
15 | notice, this list of conditions and the following disclaimer in the
16 | documentation and/or other materials provided with the distribution.
17 | - Neither the name of ARM nor the names of its contributors may be used
18 | to endorse or promote products derived from this software without
19 | specific prior written permission.
20 | *
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | POSSIBILITY OF SUCH DAMAGE.
32 | ---------------------------------------------------------------------------*/
33 |
34 |
35 | #if defined ( __ICCARM__ )
36 | #pragma system_include /* treat file as system include file for MISRA check */
37 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
38 | #pragma clang system_header /* treat file as system include file */
39 | #endif
40 |
41 | #ifndef __CORE_CMINSTR_H
42 | #define __CORE_CMINSTR_H
43 |
44 |
45 | /* ########################## Core Instruction Access ######################### */
46 | /** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface
47 | Access to dedicated instructions
48 | @{
49 | */
50 |
51 | /*------------------ RealView Compiler -----------------*/
52 | #if defined ( __CC_ARM )
53 | #include "cmsis_armcc.h"
54 |
55 | /*------------------ ARM Compiler V6 -------------------*/
56 | #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
57 | #include "cmsis_armcc_V6.h"
58 |
59 | /*------------------ GNU Compiler ----------------------*/
60 | #elif defined ( __GNUC__ )
61 | #include "cmsis_gcc.h"
62 |
63 | /*------------------ ICC Compiler ----------------------*/
64 | #elif defined ( __ICCARM__ )
65 | #include
66 |
67 | /*------------------ TI CCS Compiler -------------------*/
68 | #elif defined ( __TMS470__ )
69 | #include
70 |
71 | /*------------------ TASKING Compiler ------------------*/
72 | #elif defined ( __TASKING__ )
73 | /*
74 | * The CMSIS functions have been implemented as intrinsics in the compiler.
75 | * Please use "carm -?i" to get an up to date list of all intrinsics,
76 | * Including the CMSIS ones.
77 | */
78 |
79 | /*------------------ COSMIC Compiler -------------------*/
80 | #elif defined ( __CSMC__ )
81 | #include
82 |
83 | #endif
84 |
85 | /*@}*/ /* end of group CMSIS_Core_InstructionInterface */
86 |
87 | #endif /* __CORE_CMINSTR_H */
88 |
--------------------------------------------------------------------------------
/include/nxp/system_LPC8xx.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * @file: system_LPC8xx.h
3 | * @purpose: CMSIS Cortex-M0+ Device Peripheral Access Layer Header File
4 | * for the NXP LPC8xx Device Series
5 | * @version: V1.0
6 | * @date: 16. Aug. 2012
7 | *----------------------------------------------------------------------------
8 | *
9 | * Copyright (C) 2012 ARM Limited. All rights reserved.
10 | *
11 | * ARM Limited (ARM) is supplying this software for use with Cortex-M0+
12 | * processor based microcontrollers. This file can be freely distributed
13 | * within development tools that are supporting such ARM based processors.
14 | *
15 | * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
16 | * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
18 | * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
19 | * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
20 | *
21 | ******************************************************************************/
22 |
23 |
24 | #ifndef __SYSTEM_LPC8xx_H
25 | #define __SYSTEM_LPC8xx_H
26 |
27 | #ifdef __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include
32 |
33 | /*
34 | //-------- <<< Use Configuration Wizard in Context Menu >>> ------------------
35 | */
36 |
37 | /*--------------------- Clock Configuration ----------------------------------
38 | //
39 | // Clock Configuration
40 | // System Oscillator Control Register (SYSOSCCTRL)
41 | // BYPASS: System Oscillator Bypass Enable
42 | // If enabled then PLL input (sys_osc_clk) is fed
43 | // directly from XTALIN and XTALOUT pins.
44 | // FREQRANGE: System Oscillator Frequency Range
45 | // Determines frequency range for Low-power oscillator.
46 | // <0=> 1 - 20 MHz
47 | // <1=> 15 - 25 MHz
48 | //
49 | //
50 | // Watchdog Oscillator Control Register (WDTOSCCTRL)
51 | // DIVSEL: Select Divider for Fclkana
52 | // wdt_osc_clk = Fclkana/ (2 � (1 + DIVSEL))
53 | // <0-31>
54 | // FREQSEL: Select Watchdog Oscillator Analog Output Frequency (Fclkana)
55 | // <0=> Undefined
56 | // <1=> 0.5 MHz
57 | // <2=> 0.8 MHz
58 | // <3=> 1.1 MHz
59 | // <4=> 1.4 MHz
60 | // <5=> 1.6 MHz
61 | // <6=> 1.8 MHz
62 | // <7=> 2.0 MHz
63 | // <8=> 2.2 MHz
64 | // <9=> 2.4 MHz
65 | // <10=> 2.6 MHz
66 | // <11=> 2.7 MHz
67 | // <12=> 2.9 MHz
68 | // <13=> 3.1 MHz
69 | // <14=> 3.2 MHz
70 | // <15=> 3.4 MHz
71 | //
72 | //
73 | // System PLL Control Register (SYSPLLCTRL)
74 | // F_clkout = M * F_clkin = F_CCO / (2 * P)
75 | // F_clkin must be in the range of 10 MHz to 25 MHz
76 | // F_CCO must be in the range of 156 MHz to 320 MHz
77 | // MSEL: Feedback Divider Selection
78 | // M = MSEL + 1
79 | // <0-31>
80 | // PSEL: Post Divider Selection
81 | // <0=> P = 1
82 | // <1=> P = 2
83 | // <2=> P = 4
84 | // <3=> P = 8
85 | //
86 | //
87 | // System PLL Clock Source Select Register (SYSPLLCLKSEL)
88 | // SEL: System PLL Clock Source
89 | // <0=> IRC Oscillator
90 | // <1=> System Oscillator
91 | // <2=> Reserved
92 | // <3=> CLKIN pin
93 | //
94 | //
95 | // Main Clock Source Select Register (MAINCLKSEL)
96 | // SEL: Clock Source for Main Clock
97 | // <0=> IRC Oscillator
98 | // <1=> Input Clock to System PLL
99 | // <2=> WDT Oscillator
100 | // <3=> System PLL Clock Out
101 | //
102 | //
103 | // System AHB Clock Divider Register (SYSAHBCLKDIV)
104 | // DIV: System AHB Clock Divider
105 | // Divides main clock to provide system clock to core, memories, and peripherals.
106 | // 0 = is disabled
107 | // <0-255>
108 | //
109 | //
110 | */
111 |
112 | // 30 MHz main clock via PLL and internal RC oscillator
113 | // According to the NXP tech support to access time of the internal flash
114 | // is 24ns and zero waitstate access is still possible at 30 Mhz.
115 | //
116 | // PLL is set to 60 MHz
117 | // AHBClkdiv divides the clock by 2
118 |
119 | #define CLOCK_SETUP 1
120 | #define SYSOSCCTRL_Val 0x00000000 // Reset: 0x000
121 | #define WDTOSCCTRL_Val 0x00000000 // Reset: 0x000
122 | #define SYSPLLCTRL_Val 0x00000024 // Reset: 0x000
123 | #define SYSPLLCLKSEL_Val 0x00000000 // Reset: 0x000
124 | #define MAINCLKSEL_Val 0x00000003 // Reset: 0x000
125 | #define SYSAHBCLKDIV_Val 0x00000002 // Reset: 0x001
126 |
127 |
128 |
129 | /*
130 | //-------- <<< end of configuration section >>> ------------------------------
131 | */
132 |
133 | /*----------------------------------------------------------------------------
134 | Check the register settings
135 | *----------------------------------------------------------------------------*/
136 | #define CHECK_RANGE(val, min, max) ((val < min) || (val > max))
137 | #define CHECK_RSVD(val, mask) (val & mask)
138 |
139 | /* Clock Configuration -------------------------------------------------------*/
140 | #if (CHECK_RSVD((SYSOSCCTRL_Val), ~0x00000003))
141 | #error "SYSOSCCTRL: Invalid values of reserved bits!"
142 | #endif
143 |
144 | #if (CHECK_RSVD((WDTOSCCTRL_Val), ~0x000001FF))
145 | #error "WDTOSCCTRL: Invalid values of reserved bits!"
146 | #endif
147 |
148 | #if (CHECK_RANGE((SYSPLLCLKSEL_Val), 0, 3))
149 | #error "SYSPLLCLKSEL: Value out of range!"
150 | #endif
151 |
152 | #if (CHECK_RSVD((SYSPLLCTRL_Val), ~0x000001FF))
153 | #error "SYSPLLCTRL: Invalid values of reserved bits!"
154 | #endif
155 |
156 | #if (CHECK_RSVD((MAINCLKSEL_Val), ~0x00000003))
157 | #error "MAINCLKSEL: Invalid values of reserved bits!"
158 | #endif
159 |
160 | #if (CHECK_RANGE((SYSAHBCLKDIV_Val), 0, 255))
161 | #error "SYSAHBCLKDIV: Value out of range!"
162 | #endif
163 |
164 |
165 | /*----------------------------------------------------------------------------
166 | DEFINES
167 | *----------------------------------------------------------------------------*/
168 |
169 | /*----------------------------------------------------------------------------
170 | Define clocks
171 | *----------------------------------------------------------------------------*/
172 | #define __XTAL (12000000UL) /* Oscillator frequency */
173 | #define __SYS_OSC_CLK ( __XTAL) /* Main oscillator frequency */
174 | #define __IRC_OSC_CLK (12000000UL) /* Internal RC oscillator frequency */
175 | #define __CLKIN_CLK (12000000UL) /* CLKIN pin frequency */
176 |
177 |
178 | #define __FREQSEL ((WDTOSCCTRL_Val >> 5) & 0x0F)
179 | #define __DIVSEL (((WDTOSCCTRL_Val & 0x1F) << 1) + 2)
180 |
181 | #if (CLOCK_SETUP) /* Clock Setup */
182 | #if (__FREQSEL == 0)
183 | #define __WDT_OSC_CLK ( 0) /* undefined */
184 | #elif (__FREQSEL == 1)
185 | #define __WDT_OSC_CLK ( 500000 / __DIVSEL)
186 | #elif (__FREQSEL == 2)
187 | #define __WDT_OSC_CLK ( 800000 / __DIVSEL)
188 | #elif (__FREQSEL == 3)
189 | #define __WDT_OSC_CLK (1100000 / __DIVSEL)
190 | #elif (__FREQSEL == 4)
191 | #define __WDT_OSC_CLK (1400000 / __DIVSEL)
192 | #elif (__FREQSEL == 5)
193 | #define __WDT_OSC_CLK (1600000 / __DIVSEL)
194 | #elif (__FREQSEL == 6)
195 | #define __WDT_OSC_CLK (1800000 / __DIVSEL)
196 | #elif (__FREQSEL == 7)
197 | #define __WDT_OSC_CLK (2000000 / __DIVSEL)
198 | #elif (__FREQSEL == 8)
199 | #define __WDT_OSC_CLK (2200000 / __DIVSEL)
200 | #elif (__FREQSEL == 9)
201 | #define __WDT_OSC_CLK (2400000 / __DIVSEL)
202 | #elif (__FREQSEL == 10)
203 | #define __WDT_OSC_CLK (2600000 / __DIVSEL)
204 | #elif (__FREQSEL == 11)
205 | #define __WDT_OSC_CLK (2700000 / __DIVSEL)
206 | #elif (__FREQSEL == 12)
207 | #define __WDT_OSC_CLK (2900000 / __DIVSEL)
208 | #elif (__FREQSEL == 13)
209 | #define __WDT_OSC_CLK (3100000 / __DIVSEL)
210 | #elif (__FREQSEL == 14)
211 | #define __WDT_OSC_CLK (3200000 / __DIVSEL)
212 | #else
213 | #define __WDT_OSC_CLK (3400000 / __DIVSEL)
214 | #endif
215 |
216 | /* sys_pllclkin calculation */
217 | #if ((SYSPLLCLKSEL_Val & 0x03) == 0)
218 | #define __SYS_PLLCLKIN (__IRC_OSC_CLK)
219 | #elif ((SYSPLLCLKSEL_Val & 0x03) == 1)
220 | #define __SYS_PLLCLKIN (__SYS_OSC_CLK)
221 | #elif ((SYSPLLCLKSEL_Val & 0x03) == 3)
222 | #define __SYS_PLLCLKIN (__CLKIN_CLK)
223 | #else
224 | #define __SYS_PLLCLKIN (0)
225 | #endif
226 |
227 | #define __SYS_PLLCLKOUT (__SYS_PLLCLKIN * ((SYSPLLCTRL_Val & 0x01F) + 1))
228 |
229 | /* main clock calculation */
230 | #if ((MAINCLKSEL_Val & 0x03) == 0)
231 | #define __MAIN_CLOCK (__IRC_OSC_CLK)
232 | #elif ((MAINCLKSEL_Val & 0x03) == 1)
233 | #define __MAIN_CLOCK (__SYS_PLLCLKIN)
234 | #elif ((MAINCLKSEL_Val & 0x03) == 2)
235 | #if (__FREQSEL == 0)
236 | #error "MAINCLKSEL: WDT Oscillator selected but FREQSEL is undefined!"
237 | #else
238 | #define __MAIN_CLOCK (__WDT_OSC_CLK)
239 | #endif
240 | #elif ((MAINCLKSEL_Val & 0x03) == 3)
241 | #define __MAIN_CLOCK (__SYS_PLLCLKOUT)
242 | #else
243 | #define __MAIN_CLOCK (0)
244 | #endif
245 |
246 | #define __SYSTEM_CLOCK (__MAIN_CLOCK / SYSAHBCLKDIV_Val)
247 |
248 | #else
249 | #define __SYSTEM_CLOCK (__IRC_OSC_CLK)
250 | #endif // CLOCK_SETUP
251 |
252 |
253 | extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
254 |
255 | /**
256 | * Initialize the system
257 | *
258 | * @param none
259 | * @return none
260 | *
261 | * @brief Setup the microcontroller system.
262 | * Initialize the System and update the SystemCoreClock variable.
263 | */
264 | extern void SystemInit (void);
265 |
266 | /**
267 | * Update SystemCoreClock variable
268 | *
269 | * @param none
270 | * @return none
271 | *
272 | * @brief Updates the SystemCoreClock with current core Clock
273 | * retrieved from cpu registers.
274 | */
275 | extern void SystemCoreClockUpdate (void);
276 |
277 | #ifdef __cplusplus
278 | }
279 | #endif
280 |
281 | #endif /* __SYSTEM_LPC8xx_H */
282 |
--------------------------------------------------------------------------------
/init/lpc8xx_ram_init.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | #if 0 // now set in Makefile.base (or overriden by commandline/sub-makefile)
6 | #undef ALL_HANDLERS_DEFAULT
7 | #define WEAK_FUNCTIONS
8 | #endif
9 |
10 |
11 | void init(void);
12 | #ifdef ALL_HANDLERS_DEFAULT
13 | void Default_Handler (void);
14 | #else
15 | void NMI_Handler (void),
16 | HardFault_Handler (void),
17 | SVCall_Handler (void),
18 | PendSV_Handler (void),
19 | SysTick_Handler (void),
20 | /* External interrupt handlers follow */
21 | SPI0_IRQHandler (void),
22 | SPI1_IRQHandler (void),
23 | UART0_IRQHandler (void),
24 | UART1_IRQHandler (void),
25 | UART2_IRQHandler (void),
26 | Reserved1_IRQHandler (void),
27 | #ifdef LPC82X
28 | I2C1_IRQHandler (void),
29 | I2C0_IRQHandler (void),
30 | #endif
31 | #ifdef LPC81X
32 | I2C_IRQHandler (void),
33 | #endif
34 | SCT_IRQHandler (void),
35 | MRT_IRQHandler (void),
36 | CMP_IRQHandler (void),
37 | WDT_IRQHandler (void),
38 | BOD_IRQHandler (void),
39 | WKT_IRQHandler (void),
40 | #ifdef LPC82X
41 | ISE_ADC_SEQA_IRQHandler (void),
42 | ISE_ADC_SEQB_IRQHandler (void),
43 | ISE_ADC_THCMP_IRQHandler(void),
44 | ISE_ADC_OVR_IRQHandler (void),
45 | ISE_SDMA_IRQHandler (void),
46 | ISE_I2C2_IRQHandler (void),
47 | ISE_I2C3_IRQHandler (void),
48 | #endif
49 | Reserved11_IRQHandler (void),
50 | PININT0_IRQHandler (void),
51 | PININT1_IRQHandler (void),
52 | PININT2_IRQHandler (void),
53 | PININT3_IRQHandler (void),
54 | PININT4_IRQHandler (void),
55 | PININT5_IRQHandler (void),
56 | PININT6_IRQHandler (void),
57 | PININT7_IRQHandler (void);
58 | #endif
59 |
60 | int main(void);
61 |
62 | // The following are 'declared' in the linker script
63 | extern uint8_t BSS_START;
64 | extern uint8_t BSS_END;
65 | extern uint8_t TOP_OF_STACK;
66 |
67 | // the section "isr_vectors" is placed at the beginning of ram
68 | // by the linker script
69 | void *INTERRUPT_VECTORS[] __attribute__((section(".isr_vectors"))) = {
70 | (void *)&TOP_OF_STACK, /* Top of stack */
71 | init, /* Reset Handler */
72 | #ifdef ALL_HANDLERS_DEFAULT
73 | Default_Handler, /* NMI */
74 | Default_Handler, /* Hard Fault */
75 | 0, /* reserved */
76 | 0, /* reserved */
77 | 0, /* reserved */
78 | 0, /* reserved */
79 | 0, /* reserved */
80 | 0, /* reserved */
81 | 0, /* reserved */
82 | Default_Handler, /* SVCall */
83 | 0, /* reserved */
84 | 0, /* reserved */
85 | Default_Handler, /* PendSV */
86 | Default_Handler, /* SysTick */
87 | /* External interrupt handlers follow */
88 | Default_Handler, /* 0 SPI0 controller */
89 | Default_Handler, /* 1 SPI1 controller */
90 | Default_Handler, /* 2 reserved */
91 | Default_Handler, /* 3 UART0 */
92 | Default_Handler, /* 4 UART1 */
93 | Default_Handler, /* 5 UART2 */
94 | Default_Handler, /* 6 reserved */
95 | #ifdef LPC81X
96 | Default_Handler, /* 7 reserved */
97 | Default_Handler, /* 8 I2C controller */
98 | #endif
99 | #ifdef LPC82X
100 | Default_Handler, /* 8 I2C1 controller */
101 | Default_Handler, /* 8 I2C0 controller */
102 | #endif
103 | Default_Handler, /* 9 Smart Counter Timer */
104 | Default_Handler, /* 10 Multi-Rate Timer */
105 | Default_Handler, /* 11 Comparator */
106 | Default_Handler, /* 12 PIO1 (0:11) */
107 | Default_Handler, /* 13 Brown Out Detect */
108 | Default_Handler, /* 14 reserved */
109 | Default_Handler, /* 15 Wakeup timer */
110 | #ifdef LPC81X
111 | Default_Handler, /* 16 reserved */
112 | Default_Handler, /* 17 reserved */
113 | Default_Handler, /* 18 reserved */
114 | Default_Handler, /* 19 reserved */
115 | Default_Handler, /* 20 reserved */
116 | Default_Handler, /* 21 reserved */
117 | Default_Handler, /* 22 reserved */
118 | #endif
119 | #ifdef LPC82X
120 | Default_Handler, /* 16 ISE_ADC_SEQA */
121 | Default_Handler, /* 17 ISE_ADC_SEQB */
122 | Default_Handler, /* 18 ISE_ADC_THCMP */
123 | Default_Handler, /* 19 ISE_ADC_OVR */
124 | Default_Handler, /* 20 ISE_SDMA */
125 | Default_Handler, /* 21 ISE_I2C2 */
126 | Default_Handler, /* 22 ISE_I2C3 */
127 | #endif
128 | Default_Handler, /* 23 reserved */
129 | Default_Handler, /* 24 PIO INT0 */
130 | Default_Handler, /* 25 PIO INT1 */
131 | Default_Handler, /* 26 PIO INT2 */
132 | Default_Handler, /* 27 PIO INT3 */
133 | Default_Handler, /* 28 PIO INT4 */
134 | Default_Handler, /* 29 PIO INT5 */
135 | Default_Handler, /* 30 PIO INT6 */
136 | Default_Handler, /* 31 PIO INT7 */
137 | #else
138 | NMI_Handler, /* NMI */
139 | HardFault_Handler, /* Hard Fault */
140 | 0, /* reserved */
141 | 0, /* reserved */
142 | 0, /* reserved */
143 | 0, /* reserved */
144 | 0, /* reserved */
145 | 0, /* reserved */
146 | 0, /* reserved */
147 | SVCall_Handler, /* SVCall */
148 | 0, /* reserved */
149 | 0, /* reserved */
150 | PendSV_Handler, /* PendSV */
151 | SysTick_Handler, /* SysTick */
152 | /* External interrupt handlers follow */
153 | SPI0_IRQHandler, /* 0 SPI0 controller */
154 | SPI1_IRQHandler, /* 1 SPI1 controller */
155 | 0, /* 2 reserved */
156 | UART0_IRQHandler, /* 3 UART0 */
157 | UART1_IRQHandler, /* 4 UART1 */
158 | UART2_IRQHandler, /* 5 UART2 */
159 | Reserved1_IRQHandler, /* 6 reserved */
160 | #ifdef LPC81X
161 | 0, /* 7 reserved */
162 | I2C_IRQHandler, /* 8 I2C controller */
163 | #endif
164 | #ifdef LPC82X
165 | I2C1_IRQHandler, /* 8 I2C1 controller */
166 | I2C0_IRQHandler, /* 8 I2C0 controller */
167 | #endif
168 | SCT_IRQHandler, /* 9 Smart Counter Timer */
169 | MRT_IRQHandler, /* 10 Multi-Rate Timer */
170 | CMP_IRQHandler, /* 11 Comparator */
171 | WDT_IRQHandler, /* 12 PIO1 (0:11) */
172 | BOD_IRQHandler, /* 13 Brown Out Detect */
173 | 0, /* 14 reserved */
174 | WKT_IRQHandler, /* 15 Wakeup timer */
175 | #ifdef LPC81X
176 | 0, /* 16 reserved */
177 | 0, /* 17 reserved */
178 | 0, /* 18 reserved */
179 | 0, /* 19 reserved */
180 | 0, /* 20 reserved */
181 | 0, /* 21 reserved */
182 | 0, /* 22 reserved */
183 | #endif
184 | #ifdef LPC82X
185 | ISE_ADC_SEQA_IRQHandler, /* 16 ISE_ADC_SEQA */
186 | ISE_ADC_SEQB_IRQHandler, /* 17 ISE_ADC_SEQB */
187 | ISE_ADC_THCMP_IRQHandler, /* 18 ISE_ADC_THCMP */
188 | ISE_ADC_OVR_IRQHandler, /* 19 ISE_ADC_OVR */
189 | ISE_SDMA_IRQHandler, /* 20 ISE_SDMA */
190 | ISE_I2C2_IRQHandler, /* 21 ISE_I2C2 */
191 | ISE_I2C3_IRQHandler, /* 22 ISE_I2C3 */
192 | #endif
193 | Reserved11_IRQHandler, /* 23 reserved */
194 | PININT0_IRQHandler, /* 24 PIO INT0 */
195 | PININT1_IRQHandler, /* 25 PIO INT1 */
196 | PININT2_IRQHandler, /* 26 PIO INT2 */
197 | PININT3_IRQHandler, /* 27 PIO INT3 */
198 | PININT4_IRQHandler, /* 28 PIO INT4 */
199 | PININT5_IRQHandler, /* 29 PIO INT5 */
200 | PININT6_IRQHandler, /* 30 PIO INT6 */
201 | PININT7_IRQHandler, /* 31 PIO INT7 */
202 | #endif
203 | };
204 |
205 |
206 |
207 | #if 0
208 | // from
209 | // Projects/STM32L476G-Discovery/Templates_LL/Src/system_stm32l4xx.c
210 | // SystemInit(void)
211 | void set_defaults()
212 | {
213 | /* Reset the RCC clock configuration */
214 | RCC->CR |= RCC_CR_MSION;
215 |
216 | RCC->CFGR = 0x00000000;
217 |
218 | /* Reset HSEON, CSSON , HSION, and PLLON bits */
219 | RCC->CR &= ~( RCC_CR_HSEON
220 | | RCC_CR_CSSON
221 | | RCC_CR_HSION
222 | | RCC_CR_PLLON
223 | | RCC_CR_PLLSAI1ON
224 | | RCC_CR_PLLSAI2ON);
225 |
226 | /* Reset PLLCFGR register */
227 | RCC->PLLCFGR = 0x00001000;
228 |
229 | /* Reset HSEBYP bit */
230 | RCC->CR &= (uint32_t)0xFFFBFFFF;
231 |
232 | /* Disable all interrupts */
233 | RCC->CIER = 0x00000000;
234 | }
235 | #endif
236 |
237 |
238 |
239 | void __attribute__ ((isr)) init()
240 | {
241 | uint8_t *dest;
242 | uint32_t len;
243 |
244 | // zero out the uninitialized global/static variables
245 | dest = &BSS_START;
246 | len = &BSS_END - &BSS_START;
247 | while (len--)
248 | *dest++=0;
249 |
250 | // set CPU's vector table address
251 | SCB->VTOR = (uint32_t)INTERRUPT_VECTORS;
252 |
253 | #if 0
254 | set_defaults();
255 | #endif
256 |
257 | // start program
258 | main();
259 | }
260 |
261 |
262 |
263 | #ifdef WEAK_FUNCTIONS
264 | #define MAYBE_WEAK __attribute__((weak))
265 | #else
266 | #define MAYBE_WEAK
267 | #endif
268 |
269 |
270 | #ifdef ALL_HANDLERS_DEFAULT
271 | MAYBE_WEAK void Default_Handler()
272 | {
273 | while(1);
274 | }
275 | #else
276 | MAYBE_WEAK void NMI_Handler () { while (1); }
277 | MAYBE_WEAK void HardFault_Handler () { while (1); }
278 | MAYBE_WEAK void SVCall_Handler () { while (1); }
279 | MAYBE_WEAK void PendSV_Handler () { while (1); }
280 | MAYBE_WEAK void SysTick_Handler () { while (1); }
281 | /* External interrupt handlers follow */
282 | MAYBE_WEAK void SPI0_IRQHandler () { while (1); }
283 | MAYBE_WEAK void SPI1_IRQHandler () { while (1); }
284 | MAYBE_WEAK void UART0_IRQHandler () { while (1); }
285 | MAYBE_WEAK void UART1_IRQHandler () { while (1); }
286 | MAYBE_WEAK void UART2_IRQHandler () { while (1); }
287 | MAYBE_WEAK void Reserved1_IRQHandler () { while (1); }
288 | #ifdef LPC81X
289 | MAYBE_WEAK void I2C_IRQHandler () { while (1); }
290 | #endif
291 | #ifdef LPC82X
292 | MAYBE_WEAK void I2C1_IRQHandler () { while (1); }
293 | MAYBE_WEAK void I2C0_IRQHandler () { while (1); }
294 | #endif
295 | MAYBE_WEAK void SCT_IRQHandler () { while (1); }
296 | MAYBE_WEAK void MRT_IRQHandler () { while (1); }
297 | MAYBE_WEAK void CMP_IRQHandler () { while (1); }
298 | MAYBE_WEAK void WDT_IRQHandler () { while (1); }
299 | MAYBE_WEAK void BOD_IRQHandler () { while (1); }
300 | MAYBE_WEAK void WKT_IRQHandler () { while (1); }
301 | #ifdef LPC82X
302 | MAYBE_WEAK void ISE_ADC_SEQA_IRQHandler () { while (1); }
303 | MAYBE_WEAK void ISE_ADC_SEQB_IRQHandler () { while (1); }
304 | MAYBE_WEAK void ISE_ADC_THCMP_IRQHandler() { while (1); }
305 | MAYBE_WEAK void ISE_ADC_OVR_IRQHandler () { while (1); }
306 | MAYBE_WEAK void ISE_SDMA_IRQHandler () { while (1); }
307 | MAYBE_WEAK void ISE_I2C2_IRQHandler () { while (1); }
308 | MAYBE_WEAK void ISE_I2C3_IRQHandler () { while (1); }
309 | #endif
310 | MAYBE_WEAK void Reserved11_IRQHandler () { while (1); }
311 | MAYBE_WEAK void PININT0_IRQHandler () { while (1); }
312 | MAYBE_WEAK void PININT1_IRQHandler () { while (1); }
313 | MAYBE_WEAK void PININT2_IRQHandler () { while (1); }
314 | MAYBE_WEAK void PININT3_IRQHandler () { while (1); }
315 | MAYBE_WEAK void PININT4_IRQHandler () { while (1); }
316 | MAYBE_WEAK void PININT5_IRQHandler () { while (1); }
317 | MAYBE_WEAK void PININT6_IRQHandler () { while (1); }
318 | MAYBE_WEAK void PININT7_IRQHandler () { while (1); }
319 | #endif
320 |
--------------------------------------------------------------------------------
/ld/lpc824_ram.ld:
--------------------------------------------------------------------------------
1 | /* Linker script for NXP LPC824 */
2 |
3 | ENTRY(init)
4 |
5 | MEMORY
6 | {
7 | FLASH (rx) : org = 0x00000000, LENGTH = 32K
8 | RAM (rwx) : org = 0x10000000, LENGTH = 8K
9 | }
10 |
11 | PROVIDE(MINIMUM_STACK_SIZE = 32);
12 |
13 | SECTIONS
14 | {
15 | . = ORIGIN(RAM);
16 | .text : {
17 | *(.isr_vectors); /* The interrupt vectors */
18 | *(.text);
19 | } > RAM
20 |
21 | .data : {
22 | . = ALIGN(4);
23 | *(.data);
24 | } > RAM
25 |
26 | BSS_START = .;
27 | .bss : {
28 | . = ALIGN(4);
29 | *(.bss);
30 | } > RAM
31 | BSS_END = .;
32 |
33 | end = .; /* for gnu-arm libc.a */
34 |
35 | RAM_BASE_ADDR = ORIGIN(RAM);
36 | FLASH_BASE_ADDR = ORIGIN(FLASH);
37 | TOP_OF_STACK = ORIGIN(RAM) + LENGTH(RAM);
38 |
39 | ASSERT(end + MINIMUM_STACK_SIZE < TOP_OF_STACK, "too big to fit in RAM")
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/markcharl.gdb:
--------------------------------------------------------------------------------
1 | # GDB bug prevents referencing "keys:" label in main()
2 |
3 | dprintf main.c:135, \
4 | "%c%c%c%c\n%c%c%c%c\n%c%c%c%c\n\n", \
5 | (keys_mapd & 0x800) ? '*' : '.', \
6 | (keys_mapd & 0x400) ? '*' : '.', \
7 | (keys_mapd & 0x200) ? '*' : '.', \
8 | (keys_mapd & 0x100) ? '*' : '.', \
9 | (keys_mapd & 0x080) ? '*' : '.', \
10 | (keys_mapd & 0x040) ? '*' : '.', \
11 | (keys_mapd & 0x020) ? '*' : '.', \
12 | (keys_mapd & 0x010) ? '*' : '.', \
13 | (keys_mapd & 0x008) ? '*' : '.', \
14 | (keys_mapd & 0x004) ? '*' : '.', \
15 | (keys_mapd & 0x002) ? '*' : '.', \
16 | (keys_mapd & 0x001) ? '*' : '.'
17 |
18 | disable
19 |
--------------------------------------------------------------------------------
/source/charlieplex.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | #include
6 |
7 |
8 |
9 |
10 | static void set_as_input(
11 | const uint32_t gpio_bit ,
12 | volatile uint32_t* const iocon_reg)
13 | {
14 | // configure GPIO port as input
15 | LPC_GPIO_PORT->DIR0 &= ~gpio_bit;
16 | LPC_GPIO_PORT->CLR0 |= gpio_bit;
17 |
18 | // enable pulldown resistor
19 | CHANGE_BITS(*iocon_reg, IOCON_MODES_PULL_MASK, IOCON_MODES_PULL_DOWN);
20 | }
21 |
22 |
23 |
24 | void plex(
25 | const uint8_t const *gpio_ndxs ,
26 | volatile uint32_t* const *iocon_regs,
27 | const uint8_t num_gpios )
28 | {
29 | // enable GPIO
30 | LPC_SYSCON->SYSAHBCLKCTRL |= SYS_AHB_CLK_CTRL_GPIO_BIT;
31 |
32 | // enable IOCON
33 | LPC_SYSCON->SYSAHBCLKCTRL |= SYS_AHB_CLK_CTRL_IOCON_BIT;
34 |
35 | // initialize all IO ports as inputs
36 | for (uint8_t ndx = 0 ; ndx < num_gpios ; ++ndx)
37 | set_as_input(gpio_ndxs[ndx], iocon_regs[ndx]);
38 | }
39 |
40 |
41 |
42 | uint32_t scan(
43 | const uint8_t const *gpio_ndxs ,
44 | const uint32_t const *gpio_bits ,
45 | volatile uint32_t* const *iocon_regs,
46 | const uint8_t num_gpios )
47 | {
48 | uint32_t keys_pressed = 0;
49 | uint8_t out_shift = 0;
50 |
51 | for (uint8_t out_ndx = 0 ; out_ndx < num_gpios ; ++out_ndx) {
52 | // configure one IO as output, disable pulldown resistor, output 1
53 | //
54 | LPC_GPIO_PORT->DIR0 |= gpio_bits[out_ndx];
55 |
56 | CHANGE_BITS(*iocon_regs[out_ndx],
57 | IOCON_MODES_PULL_MASK,
58 | IOCON_MODES_PULL_NONE);
59 |
60 | LPC_GPIO_PORT->W0[gpio_ndxs[out_ndx]] = 1;
61 |
62 | // read other IOs
63 | //
64 | uint8_t in_ndx = 0,
65 | in_shift = 0;
66 |
67 | for ( ; in_ndx < out_ndx ; ++in_ndx, ++in_shift)
68 | if (LPC_GPIO_PORT->W0[gpio_ndxs[in_ndx]])
69 | keys_pressed |= 1 << out_shift << in_shift;
70 |
71 | ++in_ndx;
72 |
73 | for ( ; in_ndx < num_gpios ; ++in_ndx, ++in_shift)
74 | if (LPC_GPIO_PORT->W0[gpio_ndxs[in_ndx]])
75 | keys_pressed |= 1 << out_shift << in_shift;
76 |
77 |
78 | // reset output IO back to input
79 | set_as_input(gpio_bits[out_ndx], iocon_regs[out_ndx]);
80 |
81 | // for next output and set of inputs
82 | out_shift += num_gpios - 1;
83 | }
84 |
85 | return keys_pressed;
86 | }
87 |
--------------------------------------------------------------------------------
/source/display.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | #include
6 |
7 |
8 | #define SPI LPC_SPI0
9 | static const uint32_t SYS_AHB_CLK_CTRL_SPI_BIT = SYS_AHB_CLK_CTRL_SPI0_BIT;
10 |
11 | static volatile uint32_t *CLCK_IOCON_REG = &LPC_IOCON-> PIO0_9, // match GPIO
12 | *DATA_IOCON_REG = &LPC_IOCON->PIO0_15, // match GPIO
13 | *CLCK_SWM_REG = &LPC_SWM->PINASSIGN3,
14 | *DATA_SWM_REG = &LPC_SWM->PINASSIGN4;
15 |
16 | static const uint32_t CLCK_SWM_MASK = SWM_PINASSIGN3_SPI0_SCLK_IO_MASK,
17 | DATA_SWM_MASK = SWM_PINASSIGN4_SPI0_MOSI_IO_MASK;
18 |
19 | static const uint8_t CLCK_GPIO_NDX = PIO_0_9_POS, // match IOCON
20 | DATA_GPIO_NDX = PIO_0_15_POS, // match IOCON
21 | CLCK_SWM_POS = SWM_PINASSIGN3_SPI0_SCLK_IO_POS,
22 | DATA_SWM_POS = SWM_PINASSIGN4_SPI0_MOSI_IO_POS;
23 |
24 | static const uint32_t CLCK_SWM_BITS = CLCK_GPIO_NDX << CLCK_SWM_POS,
25 | DATA_SWM_BITS = DATA_GPIO_NDX << DATA_SWM_POS;
26 |
27 | static const uint16_t CLOCK_DIVISOR = 1;
28 |
29 |
30 | #define NUM_APA102S 12
31 | #define FIRST_APA102_NDX 1
32 |
33 | static const uint32_t APA102_START = 0x00000000,
34 | APA102_FINISH = 0x00000000,
35 | APA102_BLACK = 0xe1000000,
36 | APA102_WHITE = 0xe1080808;
37 |
38 | static uint32_t apa102s[NUM_APA102S + 2];
39 |
40 |
41 |
42 |
43 | void display_init()
44 | {
45 | apa102s[ 0] = APA102_START ;
46 | apa102s[NUM_APA102S - 1] = APA102_FINISH;
47 |
48 | // enable switch matrix clock
49 | LPC_SYSCON->SYSAHBCLKCTRL |= SYS_AHB_CLK_CTRL_SWM_BIT;
50 |
51 | // configure mapping, SPI clock/data -> GPIO ports
52 | CHANGE_BITS(*CLCK_SWM_REG, CLCK_SWM_MASK, CLCK_SWM_BITS);
53 | CHANGE_BITS(*DATA_SWM_REG, DATA_SWM_MASK, DATA_SWM_BITS);
54 |
55 | // disable switch matrix clock
56 | LPC_SYSCON->SYSAHBCLKCTRL &= ~SYS_AHB_CLK_CTRL_SWM_BIT;
57 |
58 | // enable SPI
59 | LPC_SYSCON->SYSAHBCLKCTRL |= SYS_AHB_CLK_CTRL_SPI_BIT;
60 |
61 | // configure SPI
62 | //
63 | SPI->DIV = CLOCK_DIVISOR ;
64 | SPI->CFG = SPI_CFG_ENABLE_BIT | SPI_CFG_MASTER_BIT;
65 | }
66 |
67 |
68 |
69 |
70 |
71 | void display(
72 | const uint16_t keys_bits)
73 | {
74 | uint32_t bit = 1 << 11;
75 |
76 | for (uint8_t key_ndx = FIRST_APA102_NDX ;
77 | key_ndx < FIRST_APA102_NDX + NUM_APA102S ;
78 | ++key_ndx, bit >>= 1 )
79 | if (keys_bits & bit) apa102s[key_ndx] = APA102_WHITE;
80 | else apa102s[key_ndx] = APA102_BLACK;
81 |
82 |
83 | uint8_t lsbs = 0;
84 | uint16_t half ;
85 |
86 | for (uint8_t apa102_ndx = 0 ; apa102_ndx < NUM_APA102S + 2 ; ) {
87 | // wait until peripheral ready
88 | while ( (SPI->STAT & (SPI_STAT_TXRDY_BIT | SPI_STAT_STALLED_BIT))
89 | != SPI_STAT_TXRDY_BIT )
90 | asm("nop");
91 |
92 | if (lsbs ^= 1)
93 | half = (apa102s[apa102_ndx] & 0xffff0000) >> 16;
94 | else {
95 | half = apa102s[apa102_ndx] & 0x0000ffff;
96 | ++apa102_ndx ;
97 | }
98 |
99 | SPI->TXDATCTL = half
100 | | SPI_TXDATCTL_EOT_BIT
101 | | SPI_TXDATCTL_RXIGNORE_BIT
102 | | SPI_TXDATCTL_LEN_16_BITS ;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/source/lpc824_bits.h:
--------------------------------------------------------------------------------
1 | #ifndef LPC8XX_BITS_H
2 | #define LPC8XX_BITS_H
3 |
4 | #define CHANGE_BITS(REGISTER, MASK, BITS) \
5 | (REGISTER) = ((REGISTER) & ~(MASK)) | (BITS)
6 |
7 |
8 | #define SYS_AHB_CLK_CTRL_GPIO_BIT (1 << 6)
9 | #define SYS_AHB_CLK_CTRL_SWM_BIT (1 << 7)
10 | #define SYS_AHB_CLK_CTRL_SPI0_BIT (1 << 11)
11 | #define SYS_AHB_CLK_CTRL_IOCON_BIT (1 << 18)
12 | #define SYS_AHB_CLK_CTRL_ACMP_BIT (1 << 19)
13 |
14 | #define SYS_CON_PDRUNCFG_ACMP_PD_BIT (1 << 15)
15 |
16 |
17 | #define SWM_PINASSIGN3_SPI0_SCLK_IO_POS 24
18 | #define SWM_PINASSIGN4_SPI0_MOSI_IO_POS 0
19 |
20 | #define SWM_PINASSIGN3_SPI0_SCLK_IO_MASK ( 0xff \
21 | << SWM_PINASSIGN3_SPI0_SCLK_IO_POS)
22 | #define SWM_PINASSIGN4_SPI0_MOSI_IO_MASK ( 0xff \
23 | << SWM_PINASSIGN4_SPI0_MOSI_IO_POS)
24 |
25 |
26 | #define SWM_PINENABLE0_ACMP_I1_EN_BIT (1 << 0)
27 | #define SWM_PINENABLE0_ACMP_I2_EN_BIT (1 << 1)
28 | #define SWM_PINENABLE0_ACMP_I3_EN_BIT (1 << 2)
29 | #define SWM_PINENABLE0_ACMP_I4_EN_BIT (1 << 3)
30 |
31 |
32 | #define PIO_0_0_POS 0
33 | #define PIO_0_1_POS 1
34 | #define PIO_0_2_POS 2
35 | #define PIO_0_3_POS 3
36 | #define PIO_0_4_POS 4
37 | #define PIO_0_5_POS 5
38 | #define PIO_0_6_POS 6
39 | #define PIO_0_7_POS 7
40 | #define PIO_0_8_POS 8
41 | #define PIO_0_9_POS 9
42 | #define PIO_0_10_POS 10
43 | #define PIO_0_11_POS 11
44 | #define PIO_0_12_POS 12
45 | #define PIO_0_13_POS 13
46 | #define PIO_0_14_POS 14
47 | #define PIO_0_15_POS 15
48 | #define PIO_0_16_POS 16
49 | #define PIO_0_17_POS 17
50 | #define PIO_0_18_POS 18
51 | #define PIO_0_19_POS 19
52 | #define PIO_0_20_POS 20
53 | #define PIO_0_21_POS 21
54 | #define PIO_0_22_POS 22
55 | #define PIO_0_23_POS 23
56 |
57 |
58 | #define IOCON_MODES_PULL_POS 3
59 | #define IOCON_MODES_PULL_MASK (0x3 << IOCON_MODES_PULL_POS)
60 | #define IOCON_MODES_PULL_NONE (0x0 << IOCON_MODES_PULL_POS)
61 | #define IOCON_MODES_PULL_DOWN (0x1 << IOCON_MODES_PULL_POS)
62 |
63 |
64 | #define SPI_CFG_ENABLE_BIT (1 << 0)
65 | #define SPI_CFG_MASTER_BIT (1 << 2)
66 |
67 | #define SPI_STAT_TXRDY_BIT (1 << 1)
68 | #define SPI_STAT_STALLED_BIT (1 << 6)
69 |
70 | #define SPI_TXDATCTL_EOT_BIT ( 1 << 20)
71 | #define SPI_TXDATCTL_RXIGNORE_BIT ( 1 << 22)
72 | #define SPI_TXDATCTL_LEN_16_BITS (0xf << 24)
73 |
74 |
75 | #define CMP_CTRL_COMP_VP_SEL_MASK (0x7 << 8)
76 | #define CMP_CTRL_COMP_VP_SEL_LADDER_BITS (0x0 << 8)
77 | #define CMP_CTRL_COMP_VP_SEL_ACMP_I1_BITS (0x1 << 8)
78 | #define CMP_CTRL_COMP_VP_SEL_ACMP_I2_BITS (0x2 << 8)
79 | #define CMP_CTRL_COMP_VP_SEL_ACMP_I3_BITS (0x3 << 8)
80 | #define CMP_CTRL_COMP_VP_SEL_ACMP_I4_BITS (0x4 << 8)
81 | #define CMP_CTRL_COMP_VM_SEL_LADDER_BITS ( 0 << 11)
82 |
83 | #define CMP_CTRL_EDGECLR_BIT (1 << 20)
84 | #define CMP_CTRL_COMPSTAT_BIT (1 << 21)
85 |
86 | #define CMP_LADDER_LADEN_BIT ( 1 << 0)
87 | #define CMP_LADDER_LADSEL_MASK (0x1f << 1)
88 | #define CMP_LADDER_LADREF_VDD_BIT ( 0 << 6)
89 |
90 | #endif /* ifndef LPC8XX_BITS_H */
91 |
--------------------------------------------------------------------------------
/source/main.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | #include
6 |
7 |
8 |
9 |
10 | // CPU speed
11 | #define MAIN_CLOCK_DIVISOR 1
12 | #define MAIN_CLOCK_MHZ 12 // (native 12 MHz) / MAIN_CLOCK_DIVISOR
13 | #define SCAN_DELAY_MS 1000
14 | #define TICKS_PER_LOOP 16 // rough estimate
15 | #define SCAN_DELAY_LOOPS ( ((MAIN_CLOCK_MHZ * 1000000) / SCAN_DELAY_MS) \
16 | / TICKS_PER_LOOP )
17 |
18 |
19 | // keypad connections
20 | //
21 | #define BRWN_GPIO_NDX PIO_0_1_POS
22 | #define PRPL_GPIO_NDX PIO_0_23_POS
23 | #define BLUE_GPIO_NDX PIO_0_14_POS
24 | #define GRAY_GPIO_NDX PIO_0_0_POS
25 |
26 | #define BRWN_GPIO_BIT (1 << BRWN_GPIO_NDX)
27 | #define PRPL_GPIO_BIT (1 << PRPL_GPIO_NDX)
28 | #define BLUE_GPIO_BIT (1 << BLUE_GPIO_NDX)
29 | #define GRAY_GPIO_BIT (1 << GRAY_GPIO_NDX)
30 |
31 |
32 | static const uint8_t GPIO_NDXS[] = {BRWN_GPIO_NDX,
33 | PRPL_GPIO_NDX,
34 | BLUE_GPIO_NDX,
35 | GRAY_GPIO_NDX};
36 | static const uint32_t GPIO_BITS[] = {BRWN_GPIO_BIT,
37 | PRPL_GPIO_BIT,
38 | BLUE_GPIO_BIT,
39 | GRAY_GPIO_BIT};
40 | static volatile uint32_t *IOCON_REGS[] = {&LPC_IOCON->PIO0_1 ,
41 | &LPC_IOCON->PIO0_2 ,
42 | &LPC_IOCON->PIO0_14,
43 | &LPC_IOCON->PIO0_0 };
44 |
45 | #define NUM_GPIOS (sizeof(GPIO_NDXS) / sizeof(uint8_t))
46 | #define NUM_KEYS (NUM_GPIOS * (NUM_GPIOS - 1))
47 |
48 |
49 | #ifdef SWITCHABLE_KEYPAD
50 | typedef struct mapping {
51 | const uint16_t orignl,
52 | mapped;
53 | } Mapping;
54 |
55 | static const Mapping mapping[] = {{0x0200, 0x0001},
56 | {0x0001, 0x0002},
57 | {0x0002, 0x0004},
58 | {0x0004, 0x0008},
59 |
60 | {0x0008, 0x0010},
61 | {0x0400, 0x0020},
62 | {0x0010, 0x0040},
63 | {0x0020, 0x0080},
64 |
65 | {0x0040, 0x0100},
66 | {0x0080, 0x0200},
67 | {0x0800, 0x0400},
68 | {0x0100, 0x0800}};
69 | #endif
70 |
71 |
72 |
73 |
74 | uint32_t plex(const uint8_t const *gpio_ndxs ,
75 | volatile uint32_t* const *iocon_regs,
76 | const uint8_t num_gpios );
77 |
78 | uint32_t scan(const uint8_t const *gpio_ndxs ,
79 | const uint32_t const *gpio_bits ,
80 | volatile uint32_t* const *iocon_regs,
81 | const uint8_t num_gpios );
82 |
83 | #ifdef USE_DISPLAY
84 | void display_init( );
85 | void display (const uint16_t keys_down);
86 | #endif
87 |
88 |
89 |
90 |
91 | int main()
92 | {
93 | // init main clock
94 | LPC_SYSCON->SYSAHBCLKDIV = MAIN_CLOCK_DIVISOR;
95 |
96 | #ifdef USE_DISPLAY
97 | // must be before markoplex.c:init() because disables SWM clock
98 | display_init();
99 | #endif
100 |
101 | // init charlieplex or markoplex
102 | plex(GPIO_NDXS, IOCON_REGS, NUM_GPIOS);
103 |
104 |
105 |
106 | // run
107 | //
108 | volatile uint32_t scans = 0,
109 | changes = 0;
110 | volatile uint16_t prev_down = 0,
111 | keys_down ,
112 | keys_mapd ;
113 |
114 | while (1) {
115 | keys_down = scan(GPIO_NDXS, GPIO_BITS, IOCON_REGS, NUM_GPIOS );
116 |
117 | if (keys_down != prev_down) {
118 | #ifdef SWITCHABLE_KEYPAD
119 | keys_mapd = 0;
120 | for (uint8_t ndx = 0 ;
121 | ndx < sizeof(mapping) / sizeof(Mapping) ;
122 | ++ndx )
123 | if (keys_down & mapping[ndx].orignl) {
124 | keys_mapd |= mapping[ndx].mapped;
125 | asm("nop"); /* DEBUG */
126 | }
127 | #else
128 | keys_mapd = keys_down;
129 | #endif
130 |
131 | #ifdef USE_DISPLAY
132 | display(keys_mapd);
133 | #endif // ifdef USE_DISPLAY
134 |
135 | keys: asm("nop"); // for GDB dprintf
136 |
137 | // set for next loop
138 | prev_down = keys_down;
139 |
140 | ++changes;
141 | }
142 |
143 | for (uint32_t delay = 0 ; delay < SCAN_DELAY_LOOPS ; ++delay)
144 | asm("nop");
145 |
146 | ++scans;
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/source/markoplex.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | #include
6 |
7 |
8 |
9 | static const uint32_t CMP_LADDER_LADSEL_VREF_BITS = 20 << 1;
10 |
11 |
12 | // must match colr_GPIO_NDX in main.c
13 | // note is reason why has to be GPIO ports 0, 1, 14 and 23
14 |
15 | static const uint32_t BRWN_SWM_BIT = SWM_PINENABLE0_ACMP_I2_EN_BIT,
16 | PRPL_SWM_BIT = SWM_PINENABLE0_ACMP_I4_EN_BIT,
17 | BLUE_SWM_BIT = SWM_PINENABLE0_ACMP_I3_EN_BIT,
18 | GRAY_SWM_BIT = SWM_PINENABLE0_ACMP_I1_EN_BIT;
19 |
20 | static const uint32_t BRWN_CMP_BIT = CMP_CTRL_COMP_VP_SEL_ACMP_I2_BITS,
21 | PRPL_CMP_BIT = CMP_CTRL_COMP_VP_SEL_ACMP_I4_BITS,
22 | BLUE_CMP_BIT = CMP_CTRL_COMP_VP_SEL_ACMP_I3_BITS,
23 | GRAY_CMP_BIT = CMP_CTRL_COMP_VP_SEL_ACMP_I1_BITS;
24 |
25 | static const uint32_t SWM_BITS[] = {BRWN_SWM_BIT,
26 | PRPL_SWM_BIT,
27 | BLUE_SWM_BIT,
28 | GRAY_SWM_BIT},
29 | CMP_BITS[] = {BRWN_CMP_BIT,
30 | PRPL_CMP_BIT,
31 | BLUE_CMP_BIT,
32 | GRAY_CMP_BIT};
33 |
34 |
35 |
36 | void plex(
37 | const uint8_t const *gpio_ndxs ,
38 | volatile uint32_t* const *iocon_regs,
39 | const uint8_t num_gpios )
40 | {
41 | // enable GPIO
42 | LPC_SYSCON->SYSAHBCLKCTRL |= SYS_AHB_CLK_CTRL_GPIO_BIT;
43 |
44 | // enable IOCON
45 | LPC_SYSCON->SYSAHBCLKCTRL |= SYS_AHB_CLK_CTRL_IOCON_BIT;
46 |
47 | // disable pulldown resistors
48 | for (uint8_t ndx = 0 ; ndx < num_gpios ; ++ndx)
49 | CHANGE_BITS(*iocon_regs[ndx],
50 | IOCON_MODES_PULL_MASK,
51 | IOCON_MODES_PULL_NONE);
52 |
53 | // initialize analog comparator
54 | //
55 | LPC_SYSCON->SYSAHBCLKCTRL |= SYS_AHB_CLK_CTRL_ACMP_BIT;
56 |
57 | // power on by clearing bit
58 | LPC_SYSCON->PDRUNCFG &= ~SYS_CON_PDRUNCFG_ACMP_PD_BIT;
59 |
60 | LPC_CMP->LAD = CMP_LADDER_LADEN_BIT
61 | | CMP_LADDER_LADSEL_VREF_BITS
62 | | CMP_LADDER_LADREF_VDD_BIT ;
63 |
64 | // VP_SEL_LADDER_BITS temporary: will be reset to each comparator input pin
65 | LPC_CMP->CTRL = CMP_CTRL_COMP_VM_SEL_LADDER_BITS
66 | | CMP_CTRL_COMP_VM_SEL_LADDER_BITS;
67 |
68 | // set and clear to clear the COMPEDGE bit
69 | LPC_CMP->CTRL |= CMP_CTRL_EDGECLR_BIT;
70 | LPC_CMP->CTRL &= ~CMP_CTRL_EDGECLR_BIT;
71 |
72 | // initialize switch matrix and all IO ports as analog inputs
73 | //
74 |
75 | LPC_SYSCON->SYSAHBCLKCTRL |= SYS_AHB_CLK_CTRL_SWM_BIT;
76 |
77 | // enable analog comparators
78 | for (uint8_t ndx = 0 ; ndx < num_gpios ; ++ndx)
79 | LPC_SWM->PINENABLE0 &= ~SWM_BITS[ndx];
80 |
81 | }
82 |
83 |
84 |
85 |
86 | uint32_t scan(
87 | const uint8_t const *gpio_ndxs ,
88 | const uint32_t const *gpio_bits ,
89 | volatile uint32_t* const *iocon_regs,
90 | const uint8_t num_gpios )
91 | {
92 | uint32_t keys_pressed = 0;
93 | uint8_t out_shift = 0;
94 |
95 | for (uint8_t out_ndx = 0 ; out_ndx < num_gpios ; ++out_ndx) {
96 | // configure one IO as normal GPIO output, output Vdd
97 | //
98 | LPC_SWM->PINENABLE0 |= SWM_BITS [out_ndx]; // ~ACMP
99 | LPC_GPIO_PORT->DIRSET0 |= gpio_bits[out_ndx]; // set as output
100 |
101 | LPC_GPIO_PORT->W0[gpio_ndxs[out_ndx]] = 1; // output 1
102 |
103 | // read other IOs
104 | //
105 | uint8_t in_shift = 0;
106 |
107 | for (uint8_t in_ndx = 0 ; in_ndx < num_gpios ; ++in_ndx) {
108 | if (in_ndx == out_ndx) continue;
109 |
110 | CHANGE_BITS(LPC_CMP->CTRL ,
111 | CMP_CTRL_COMP_VP_SEL_MASK,
112 | CMP_BITS[in_ndx] );
113 |
114 |
115 | if (LPC_CMP->CTRL & CMP_CTRL_COMPSTAT_BIT)
116 | keys_pressed |= 1 << out_shift << in_shift;
117 |
118 | ++in_shift;
119 | }
120 |
121 | // reset output GPIO back to being analog comparator
122 | LPC_GPIO_PORT->W0[gpio_ndxs[out_ndx]] = 0; // output 0
123 |
124 | LPC_GPIO_PORT->DIRCLR0 = gpio_bits[out_ndx]; // input
125 | LPC_SWM->PINENABLE0 &= ~SWM_BITS [out_ndx]; // ACMP
126 |
127 | // for next output and set of inputs
128 | out_shift += num_gpios - 1;
129 | }
130 |
131 | return keys_pressed;
132 | }
133 |
--------------------------------------------------------------------------------