├── .github
├── FUNDING.yml
└── workflows
│ └── stale-issue-bot.yaml
├── COPYING
├── README.md
├── docs
├── API.md
├── Code_Overview.md
├── Features.md
├── Releases.md
├── Tools.md
└── img
│ ├── pico-wiring.jpg
│ └── pulseview-canbus.png
├── example
├── CMakeLists.txt
├── canbuild.docker
├── canexample.c
└── pico_sdk_import.cmake
├── pio
├── README.md
├── can2040.pio
└── pioasm.docker
├── scripts
├── bitstuf.py
└── crc.py
└── src
├── can2040.c
└── can2040.h
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: koconnor
2 |
--------------------------------------------------------------------------------
/.github/workflows/stale-issue-bot.yaml:
--------------------------------------------------------------------------------
1 | # Close and warn on tickets that have become stale
2 | name: "Close stale tickets"
3 | on:
4 | schedule:
5 | - cron: '0 3 * * *'
6 | jobs:
7 | # Check for stale issues (no updates in 2 months)
8 | stale:
9 | if: github.repository == 'KevinOConnor/can2040'
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/stale@v3
13 | with:
14 | stale-issue-message: |
15 | Hello,
16 |
17 | It looks like there hasn't been any recent updates on this
18 | github ticket. We prefer to only list tickets as "open" if
19 | they are actively being worked on. Feel free to provide an
20 | update on this ticket. Otherwise the ticket will be
21 | automatically closed in a few days.
22 |
23 | Best regards,
24 |
25 | ~ Your friendly GitIssueBot
26 |
27 | PS: I'm just an automated script, not a human being.
28 |
29 | stale-pr-message: |
30 | Hello,
31 |
32 | It looks like there hasn't been any recent updates on this
33 | github ticket. We prefer to only list tickets as "open" if
34 | they are actively being worked on. Feel free to provide an
35 | update on this ticket. Otherwise the ticket will be
36 | automatically closed in a few days.
37 |
38 | Best regards,
39 |
40 | ~ Your friendly GitIssueBot
41 |
42 | PS: I'm just an automated script, not a human being.
43 |
44 | exempt-issue-labels: 'enhancement,bug'
45 | days-before-stale: 60
46 | days-before-close: 7
47 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | The can2040 project is a software CAN bus implementation for Raspberry
2 | Pi [rp2040](https://www.raspberrypi.com/products/rp2040/) and
3 | [rp2350](https://www.raspberrypi.com/products/rp2350/)
4 | micro-controllers. It enables these chips to implement
5 | [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) using a standard CAN
6 | transceiver chip. The code supports reading and writing CAN 2.0B data
7 | frames at rates up to 1Mbit per second.
8 |
9 | For further information see:
10 | - [Features](docs/Features.md): Details about this software CAN bus
11 | implementation.
12 | - [API](docs/API.md): The can2040 programmer interface.
13 | - [Tools](docs/Tools.md): Useful testing and deployment tools.
14 | - [Code Overview](docs/Code_Overview.md): Information on can2040
15 | internals (for developers working on can2040 itself).
16 | - [Releases](docs/Releases.md): History of can2040 releases.
17 |
--------------------------------------------------------------------------------
/docs/API.md:
--------------------------------------------------------------------------------
1 | This document describes how one may use can2040 in an application.
2 |
3 | Note that can2040 uses the GNU GPLv3 license. See the [COPYING
4 | file](../COPYING) for more information.
5 |
6 | # Compiling
7 |
8 | It is possible to use the standard
9 | [pico sdk](https://github.com/raspberrypi/pico-sdk.git) to build and
10 | deploy can2040 based applications. See the
11 | [example directory](../example/) for a demo application and its
12 | corresponding cmake rules.
13 |
14 | The can2040 code can also be used in environments that do not utilize
15 | the full pico sdk. The can2040 implementation is contained in the
16 | [can2040.c](../src/can2040.c) and [can2040.h](../src/can2040.h) C
17 | files. The can2040 code should be compiled using the "gcc" C
18 | compiler. The code is intended to be compiled at `-O2` (or higher)
19 | optimization.
20 |
21 | Even when not using the full sdk, the code will require a few files
22 | from the [pico sdk](https://github.com/raspberrypi/pico-sdk.git) that
23 | must be in the include path when compiling can2040 (sdk version 1.3.0
24 | or later is required). For example:
25 | `arm-none-eabi-gcc -O2 -I/path/to/sdk/src/rp2040/ ...`
26 | If compiling for the rp2350 then pico sdk version 2.0.0 or later is
27 | required and the compiler flags must include `-DPICO_RP2350`.
28 |
29 | # Startup
30 |
31 | The following provides example startup C code for can2040:
32 |
33 | ```c
34 | static struct can2040 cbus;
35 |
36 | static void
37 | can2040_cb(struct can2040 *cd, uint32_t notify, struct can2040_msg *msg)
38 | {
39 | // Add message processing code here...
40 | }
41 |
42 | static void
43 | PIOx_IRQHandler(void)
44 | {
45 | can2040_pio_irq_handler(&cbus);
46 | }
47 |
48 | void
49 | canbus_setup(void)
50 | {
51 | uint32_t pio_num = 0;
52 | uint32_t sys_clock = SYS_CLK_HZ, bitrate = 500000;
53 | uint32_t gpio_rx = 4, gpio_tx = 5;
54 |
55 | // Setup canbus
56 | can2040_setup(&cbus, pio_num);
57 | can2040_callback_config(&cbus, can2040_cb);
58 |
59 | // Enable irqs
60 | irq_set_exclusive_handler(PIO0_IRQ_0, PIOx_IRQHandler);
61 | irq_set_priority(PIO0_IRQ_0, 1);
62 | irq_set_enabled(PIO0_IRQ_0, 1);
63 |
64 | // Start canbus
65 | can2040_start(&cbus, sys_clock, bitrate, gpio_rx, gpio_tx);
66 | }
67 | ```
68 |
69 | The `can2040.h` header file provides the definition of `struct
70 | can2040`. This definition is exported so that one may statically
71 | allocate an instance of it. (It is also valid to dynamically allocate
72 | it if desired.) The content of the `struct can2040` is considered
73 | "private" - callers should not inspect or modify its content for any
74 | reason. All interaction with can2040 is done via can2040 API
75 | functions.
76 |
77 | The can2040 code does not dynamically allocate memory; all storage is
78 | contained in the `struct can2040` that the caller allocates.
79 |
80 | # can2040_msg
81 |
82 | The `can2040.h` header file provides a definition for `struct
83 | can2040_msg`. This struct is used for transmitting and receiving CAN
84 | bus messages.
85 |
86 | The `id` field contains the CAN bus message id. It may also have the
87 | `CAN2040_ID_RTR` bit and/or `CAN2040_ID_EFF` bits set. The
88 | `CAN2040_ID_RTR` bit indicates that a "remote" frame should be used.
89 | The `CAN2040_ID_EFF` bit indicates that a 29-bit extended header
90 | should be used.
91 |
92 | The `dlc` field specifies the number of data bytes the CAN bus message
93 | contains. In accordance with the CAN bus specification, the value may
94 | be between 0 and 15, however there are at most 8 data bytes. (A dlc
95 | value between 8 to 15 will have 8 data bytes.)
96 |
97 | The `data` field contains the data bytes of the CAN bus message.
98 |
99 | # Function reference
100 |
101 | ## can2040_setup
102 |
103 | `void can2040_setup(struct can2040 *cd, uint32_t pio_num)`
104 |
105 | This function initializes the `struct can2040` passed in the `cd`
106 | parameter. The caller must either statically or dynamically allocate
107 | it prior to calling this function.
108 |
109 | The `pio_num` should be either `0` or `1` to use either the `PIO0` or
110 | `PIO1` hardware block. On the rp2350 the `pio_num` may be `2` for
111 | `PIO2`.
112 |
113 | ## can2040_callback_config
114 |
115 | `void can2040_callback_config(struct can2040 *cd, can2040_rx_cb rx_cb)`
116 |
117 | This function specifies the main can2040 callback (as specified in the
118 | `rx_cb` parameter).
119 |
120 | The `can2040_rx_cb` callback function will be invoked with each
121 | successfully received and transmitted message. It must be provided by
122 | the user code.
123 |
124 | The callback uses the function prototype:
125 | `void can2040_rx_cb(struct can2040 *cd, uint32_t notify, struct can2040_msg *msg)`
126 |
127 | The `cd` parameter of the callback contains the same pointer passed to
128 | `can2040_callback_config()`.
129 |
130 | The `notify` parameter of the callback contains one of
131 | `CAN2040_NOTIFY_RX`, `CAN2040_NOTIFY_TX`, `CAN2040_NOTIFY_ERROR`.
132 | * A `CAN2040_NOTIFY_RX` event indicates a message has been
133 | successfully read. The message contents will be in the `msg`
134 | parameter.
135 | * A `CAN2040_NOTIFY_TX` event indicates a message has been
136 | successfully transmitted on the CAN bus. The transmitted message
137 | contents will be in the `msg` parameter.
138 | * A `CAN2040_NOTIFY_ERROR` event indicates that the internal receive
139 | buffers have overflowed and that some number of CAN bus messages may
140 | have been lost. The `msg` parameter will point to an allocated but
141 | otherwise empty `struct can2040_msg` in this event.
142 |
143 | The callback is invoked in IRQ context (it is called from
144 | `can2040_pio_irq_handler()`). To keep irq latency low, it is
145 | recommended that the callback copy the given message to memory to be
146 | processed during normal (non-irq) context.
147 |
148 | The `msg` pointer is only valid during the duration of the callback.
149 | The callback code should copy any desired content from `msg` to its
150 | own storage during the callback.
151 |
152 | The callback is invoked for all valid received messages on the CAN
153 | bus. The can2040 code does not implement receive message filtering.
154 | It is expected that the caller will implement any desired filtering in
155 | their callback function.
156 |
157 | ## can2040_start
158 |
159 | `void can2040_start(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate, uint32_t gpio_rx, uint32_t gpio_tx)`
160 |
161 | This function starts the main can2040 CAN bus implementation. The
162 | provided GPIO pins will be configured and associated with the
163 | rp2040/rp2350 PIO hardware block.
164 |
165 | The `sys_clock` parameter specifies the system clock rate (for example
166 | `125000000` for an rp2040/rp2350 ARM core running at 125Mhz).
167 |
168 | The `bitrate` parameter specifies the CAN bus speed (for example
169 | `500000` for a 500Kbit/s CAN bus).
170 |
171 | The `gpio_rx` parameter specifies the gpio number that is routed to
172 | the "CAN RX" pin of the CAN bus transceiver. On rp2040 it should be
173 | between 0 and 29 (for GPIO0 to GPIO29). On the rp2350 chips it may be
174 | between 0 and 31 (for GPIO0 to GPIO31), or alternatively between 16
175 | and 47 (for GPIO16 to GPIO47) if both `gpio_rx` and `gpio_tx` are
176 | between 16 and 47.
177 |
178 | The `gpio_tx` parameter specifies the gpio number that is routed to
179 | the "CAN TX" pin of the CAN bus transceiver. On rp2040 chips it
180 | should be between 0 and 29 (for GPIO0 to GPIO29). On the rp2350 chips
181 | it may be between 0 and 31 (for GPIO0 to GPIO31), or alternatively
182 | between 16 and 47 (for GPIO16 to GPIO47) if both `gpio_rx` and
183 | `gpio_tx` are between 16 and 47.
184 |
185 | After calling this function, activity on the CAN bus may result in the
186 | user specified `can2040_rx_cb` callback being invoked.
187 |
188 | ## can2040_pio_irq_handler
189 |
190 | `void can2040_pio_irq_handler(struct can2040 *cd)`
191 |
192 | This function should be invoked on each PIO hardware IRQ event. The
193 | caller should define the underlying IRQ handler function, enable it,
194 | and arrange to call `can2040_pio_irq_handler()` with each event. The
195 | can2040 code uses the first IRQ of each PIO block (`PIO0_IRQ_0_IRQn`
196 | for PIO0, or `PIO1_IRQ_0_IRQn` for PIO1).
197 |
198 | This function is intended to be invoked from IRQ context. It is
199 | reentrant safe with respect to other can2040 function calls made on
200 | the same ARM core.
201 |
202 | ## can2040_transmit
203 |
204 | `int can2040_transmit(struct can2040 *cd, struct can2040_msg *msg)`
205 |
206 | This function schedules a message for transmission on the CAN bus.
207 | The `msg` parameter should contain a pointer to the `struct
208 | can2040_msg` that should be sent. The function returns `0` if the
209 | message is successfully queued, or a negative number if there is no
210 | space for the message in the internal queue. If scheduled, the
211 | contents of the `msg` pointer are copied to internal storage during
212 | the `can2040_transmit()` call.
213 |
214 | When a scheduled message is successfully transmitted on the CAN bus
215 | the user supplied `can2040_rx_cb` callback will be invoked with a
216 | `CAN2040_NOTIFY_TX` event.
217 |
218 | The can2040 code may buffer up to four messages for transmission. If
219 | multiple messages are buffered then they are transmitted in "first in
220 | first out" order. (The buffered transmit messages are not reordered
221 | by message id priority.)
222 |
223 | It is valid to invoke `can2040_transmit()` from the user supplied
224 | `can2040_rx_cb` callback function, however doing so is not
225 | recommended. The `can2040_transmit()` function has processing
226 | overhead (it performs CRC calculation and bitstuffing on the message)
227 | and calling it from IRQ context may increase irq latency.
228 |
229 | It is valid to invoke `can2040_transmit()` on one ARM core while the
230 | other ARM core may be running `can2040_pio_irq_handler()`.
231 |
232 | ## can2040_check_transmit
233 |
234 | `int can2040_check_transmit(struct can2040 *cd)`
235 |
236 | This function may be called to determine if there is space available
237 | to schedule a message transmission. That is, it may be used to
238 | determine if a call to `can2040_transmit()` will succeed.
239 |
240 | It is valid to invoke `can2040_check_transmit()` from the user
241 | supplied `can2040_rx_cb` callback function.
242 |
243 | It is valid to invoke `can2040_check_transmit()` on one ARM core while
244 | the other ARM core may be running `can2040_pio_irq_handler()`.
245 |
246 | ## can2040_stop
247 |
248 | `void can2040_stop(struct can2040 *cd)`
249 |
250 | This function disables processing of can2040 CAN bus messages. Upon
251 | completion of this function the user supplied `can2040_rx_cb()`
252 | callback function will no longer be invoked.
253 |
254 | If this function is called while a message is queued for transmit then
255 | it is possible that the message may be successfully transmitted
256 | without it being removed from the local transmit queue and without a
257 | `CAN2040_NOTIFY_TX` event sent to the user supplied `can2040_rx_cb()`
258 | callback function.
259 |
260 | The can2040 CAN bus processing may be restarted by calling
261 | `can2040_start()`.
262 |
263 | To clear the transmit queue before restarting, call `can2040_setup()`,
264 | `can2040_callback_config()`, and then `can2040_start()`.
265 |
266 | ## can2040_get_statistics
267 |
268 | `void can2040_get_statistics(struct can2040 *cd, struct can2040_stats *stats)`
269 |
270 | This function may be called to obtain can2040 receive and transmit
271 | statistics. This may be useful for insight on how well the CAN bus
272 | network hardware is performing.
273 |
274 | The caller must allocate a `struct can2040_stats` and pass a pointer
275 | to it in the `stats` parameter. The `can2040_get_statistics()`
276 | function will copy its internal can2040 statistics to the provided
277 | struct. The caller may then inspect its local copy of `struct
278 | can2040_stats` after the function completes.
279 |
280 | The `can2040.h` header file provides the definition for `struct
281 | can2040_stats`. It has the following fields:
282 | * `rx_total`: The total number of successfully received messages.
283 | This is the number of times that `can2040_rx_cb()` is invoked with
284 | `CAN2040_NOTIFY_RX`.
285 | * `tx_total`: The total number of successfully transmitted messages.
286 | This is the number of times that `can2040_rx_cb()` is invoked with
287 | `CAN2040_NOTIFY_TX`.
288 | * `tx_attempt`: The total number of transmit attempts. If this is
289 | more than one greater than `tx_total` it indicates some transmits
290 | were retried. A transmit may be retried due to line arbitration (a
291 | transmit attempt was interrupted by a higher priority transmission
292 | from another node on the CAN bus), due to the lack of an
293 | acknowledgment from another node on the CAN bus, or due to some
294 | other parse error during a transmit attempt.
295 | * `parse_error`: The total number of data errors observed during
296 | content parsing on the CAN bus. This may increment due to hardware
297 | noise on the CAN bus, due to error frames generated from other nodes
298 | on the CAN bus, due to lack of transmit acknowledgments on the CAN
299 | bus, or due to some other error in read data.
300 |
301 | The above counters are only set to zero during the initial call to
302 | `can2040_setup()`. One may call `can2040_get_statistics()`
303 | periodically and subtract each counter from the value found at the
304 | previous call to obtain the statistics over that discrete period.
305 | When subtracting, it is recommended to store the difference in a
306 | `uint32_t` for improved handling of 32bit counter rollovers.
307 |
308 | It is valid to invoke `can2040_get_statistics()` at any time after
309 | `can2040_setup()` is called (including from another ARM core and
310 | including from the user supplied `can2040_rx_cb` callback function).
311 |
312 | # Not reentrant safe
313 |
314 | Unless explicitly stated otherwise, the can2040 code is not reentrant
315 | safe. For example, unless stated otherwise, one may not invoke
316 | can2040 functions from IRQ context (where they might preempt a can2040
317 | function running in another context), one may not invoke can2040
318 | functions from multiple ARM cores (such that two can2040 functions
319 | could be running simultaneously), nor invoke can2040 functions from
320 | the user supplied `can2040_rx_cb` callback function.
321 |
322 | # Multiple can2040 instances
323 |
324 | Each instance of can2040 uses one of the PIO hardware blocks on the
325 | rp2040/rp2350. If there are separate CAN transceivers (and separate
326 | sets of CAN rx and CAN tx gpio pins) then one may create multiple
327 | simultaneous instances of can2040.
328 |
329 | To use this functionality, the [startup code](#startup) should be run
330 | multiple times, each with their own separate instance of a `struct
331 | can2040`.
332 |
333 | In this case, the multiple instances of can2040 do not share state.
334 | Therefore, no particular synchronization is needed between instances.
335 | That is, one must ensure each instance is not reentrant with respect
336 | to itself, but it is not required to synchronize between instances.
337 | One may run multiple can2040 instances on the same ARM core or
338 | different ARM cores.
339 |
340 | # Low interrupt latency
341 |
342 | The can2040 implementation requires low interrupt response time for
343 | proper operation. See the
344 | [Features Document](Features.md#software-utilization)
345 | for more information on the impact of latency to can2040.
346 |
347 | To ensure low-latency it is recommended to limit the amount of code
348 | that runs at a higher interrupt priority than can2040. Higher
349 | priority code would be any code that disables interrupts and any
350 | interrupt handling code that is registered with a higher priority (a
351 | lower or equal value passed to `irq_set_priority()` or
352 | `NVIC_SetPriority()`).
353 |
354 | Also consider loading the can2040 code (and any code that runs at a
355 | higher priority) into memory on the rp2040/rp2350 chip. An rp2040
356 | running at 125Mhz will take a minimum of 320ns for each 32bit load
357 | from flash. Thus, even a handful of flash accesses (to load
358 | instructions or data) may cause a delay sufficient to impact can2040.
359 | Be sure to also load the can2040 callback function into ram. Consider
360 | also loading the ARM core interrupt vector table into ram (if it is
361 | not already in ram).
362 |
363 | If building with the Pico SDK then it may be possible to load the
364 | entire application into ram by adding `-DPICO_COPY_TO_RAM` to the
365 | cmake flags (or by using something like
366 | `pico_set_binary_type(my_executable copy_to_ram)` in the cmake files).
367 |
368 | It is also possible to load just the can2040 code into ram. The
369 | specifics of doing that are beyond the scope of this document, but at
370 | a high-level it typically involves locating the build "linker script"
371 | and adding `can2040.o(.text*)` and `can2040.o(.rodata*)` to the ram
372 | segment.
373 |
374 | # Using can2040 from C++
375 |
376 | The can2040 code is intended to be compiled with gcc. If can2040.c is
377 | compiled with a C compiler and linked with a C++ application then be
378 | careful to always import the `can2040.h` header file into C++ code in
379 | "C" mode - for example:
380 |
381 | ```c
382 | extern "C" {
383 | #include "can2040.h"
384 | }
385 | ```
386 |
--------------------------------------------------------------------------------
/docs/Code_Overview.md:
--------------------------------------------------------------------------------
1 | This document is intended for developers interested in understanding
2 | the can2040 implementation itself. It provides some high-level
3 | information on the can2040 code organization and objectives.
4 |
5 | # PIO state machines
6 |
7 | The can2040 code uses the rp2040/rp2350 PIO (Programmable Input
8 | Output) hardware feature. See the [rp2040
9 | datasheet](https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html)
10 | for information on the hardware.
11 |
12 | The PIO instructions used by can2040 are contained in the can2040.c
13 | code. However, a version of the PIO instructions with additional
14 | comments and other reference information can be found in the
15 | [can2040.pio](../pio/can2040.pio) file.
16 |
17 | The rp2040 chip contains two PIO hardware blocks and each PIO hardware
18 | block contains four PIO state machines. The can2040 code uses one PIO
19 | block and uses all four state machines of that block.
20 |
21 | ## PIO "sync" state machine
22 |
23 | The main task of the PIO "sync" state machine is to synchronize bit
24 | sampling to the incoming data. This enables communication between CAN
25 | bus nodes that have a slightly different clock rate. That is, the
26 | sampling time for each transmitted bit is adjusted to account for a
27 | slightly faster or slower bitrate of the transmitter. The PIO "sync"
28 | state machine raises a "sample" irq (pio irq 4) at each sampling point
29 | and other state machines read the "CAN rx" line after receiving that
30 | signal.
31 |
32 | A secondary task of the PIO "sync" state machine is to detect when a
33 | new transmission may start. It will raise a "maytx" irq (pio irq 0)
34 | after 11 passive bits are detected (in some cases, based on settings
35 | from the ARM core, this may instead be after 17 passive bits). The
36 | "maytx" irq will also be raised if another transmitter starts a
37 | transmission after 10 passive bits. This ensures a local message
38 | transmission can participate in line arbitration and that these bit
39 | transmissions are synchronized.
40 |
41 | A third task of the PIO "sync" state machine is to disable PIO
42 | "sample" irqs when the CAN bus is idle (after ten passive bits are
43 | detected) and to resume "sample" irqs upon the start of the next
44 | message. This reduces ARM core processing overhead.
45 |
46 | ## PIO "rx" state machine
47 |
48 | The main task of the PIO "rx" state machine is to relay bits on the
49 | CAN bus to the ARM processing core. The state machine reads bits from
50 | the "CAN rx" line after each "sample" irq and accumulates the data in
51 | the rx fifo. After every 10 raw input bits the ARM core is notified
52 | of the pending data.
53 |
54 | ## PIO "match" state machine
55 |
56 | The main task of the PIO "match" state machine is to detect an
57 | anticipated CRC bit sequence and to generate a "matched" signal (PIO
58 | irq 2). This mechanism is used to transmit an ack bit (a single
59 | dominant bit) at the appropriate point in a received message so as to
60 | acknowledge that message.
61 |
62 | The "match" state machine tracks the last 21 raw bits (as read from
63 | the "CAN rx" line after each "sample" irq) along with the total number
64 | of bits that have been read since the PIO hardware block was started
65 | (stored as an 11 bit integer). The ARM core can send a 32 bit
66 | "match_key" to the PIO containing this combination of raw bits and bit
67 | position. A "matched" irq is raised when both the sampled raw bits
68 | and counter match the requested match_key.
69 |
70 | A secondary task of the PIO "match" state machine is to provide
71 | "matched" signals to the main ARM core for timely notification of
72 | message completion. The same "match_key" mechanism described above is
73 | used.
74 |
75 | ## PIO "tx" state machine
76 |
77 | The main task of the PIO "tx" state machine is to transmit messages on
78 | the "CAN tx" line. For each bit to be transmitted, the state machine
79 | sets the tx line, reads the "CAN rx" line, and will stop a
80 | transmission if a dominant/passive bit conflict is found. This
81 | enables transmissions to properly participate in CAN bus line
82 | arbitration. To transmit a message, the ARM core fills the tx fifo
83 | with the raw bits of the message and arranges for the "tx" state
84 | machine to start after a "maytx" irq. The "tx" state machine performs
85 | its own bit time synchronization to resynchronize bit timing to other
86 | simultaneous transmitters that may be transmitting at a slightly
87 | faster bit rate.
88 |
89 | A secondary task of the PIO "tx" state machine is to inject an ack bit
90 | to acknowledge messages received from other CAN bus nodes. To perform
91 | this task, the ARM core fills the tx fifo with a single dominant bit
92 | and arranges for the "tx" state machine to start after a "matched"
93 | irq. After the ack bit is transmitted the PIO "tx" state machine will
94 | raise an "ackdone" signal (PIO irq 3).
95 |
96 | # ARM core state tracking
97 |
98 | The ARM core C code must process the raw bits read from the PIO and
99 | arrange for timely signals to be sent to the PIO. In effect, the PIO
100 | could be thought of as a separate processor with four running threads.
101 | Unfortunately, due to limitations in the PIO's ability to track state,
102 | the ARM C code has a high burden to ensure proper synchronization.
103 |
104 | To facilitate this state tracking, the C code maintains three state
105 | tracking variables: `parse_state`, `report_state`, and `tx_state`.
106 |
107 | ## Parse state
108 |
109 | The `parse_state` variable tracks the current message position (eg,
110 | header, data, trailer) as data is read from the "rx" state machine
111 | fifo. When the "rx" state machine fills an rx fifo the ARM core is
112 | alerted and the ARM PIO irq handler will read that data. The raw bits
113 | are then checked for bit stuffing and the resulting unstuffed data is
114 | accumulated to assemble the incoming message.
115 |
116 | The [CAN bus wikipedia article](https://en.wikipedia.org/wiki/CAN_bus)
117 | is a useful reference for the parts of a CAN bus message and the
118 | corresponding `parse_state` states that are tracked.
119 |
120 | Each rx fifo entry is filled after every ten raw bits of data. The
121 | bits in each fifo entry will not be aligned to message boundaries (a
122 | message start-of-header bit could occur in any of the ten bits in a
123 | fifo entry). Updates to `parse_state` tracking will typically lag the
124 | actual raw bitstream seen by the PIO by a minimum of five bits, but
125 | could be much larger due to ARM core "irq latency". Also, the "sync"
126 | state machine disables "sample" irqs after ten passive bits, which
127 | could result in up to nine bits of a message not being observed by the
128 | `parse_state` tracking until the start of the next message (a
129 | potentially significant delay). The `report_state` tracker is used to
130 | account for these timing limitations.
131 |
132 | ## Report state
133 |
134 | The `report_state` tracking combines information from the rx fifo (as
135 | tracked by `parse_state`) along with direct PIO irq signals to provide
136 | more timely handling of incoming messages.
137 |
138 | The `report_state` handling has notable complexity due to its need to
139 | handle several asynchronous events - for example, the rx fifo may be
140 | one or more entries behind the PIO state, ARM core irq latency may
141 | delay observation of a PIO irq until after the PIO state has changed,
142 | a PIO irq may be observed before or after the corresponding bits are
143 | observed from the rx fifo, a scheduled PIO irq may not be scheduled in
144 | time to observe the event and thus never be received, etc. .
145 | Unfortunately, due to limitations in the PIO's ability to perform
146 | state tracking, handling this state tracking complexity in the ARM
147 | core seems to be necessary.
148 |
149 | There are five states that `report_state` may be in: `RS_IDLE`,
150 | `RS_NEED_RX_ACK`, `RS_NEED_RX_EOF`, `RS_NEED_TX_ACK`, and
151 | `RS_NEED_TX_EOF`.
152 |
153 | The main goal of the `report_state` tracking is to "look ahead" of the
154 | current message state found in `parse_state` to detect successful ack
155 | and eof states as soon as they are observed by the PIO. This allows
156 | the can2040 code to more quickly report messages to the user code.
157 | This code also arranges for the PIO to generate timely ack bits for
158 | incoming messages and to timely queue outgoing messages in the PIO so
159 | that they are available for line arbitration.
160 |
161 | ## Transmit state
162 |
163 | The `tx_state` variable tracks the current state of messages queued
164 | for transmission in the PIO "tx" state machine. It is used to
165 | determine if a message needs to be re-queued (for example, if a
166 | previous transmit attempt was preempted by a higher priority message).
167 | It is also used to determine if the current incoming message (as
168 | tracked by `parse_state`) is actually feedback from a locally
169 | transmitted message.
170 |
--------------------------------------------------------------------------------
/docs/Features.md:
--------------------------------------------------------------------------------
1 | This document describes features and limitations of the can2040 CAN
2 | bus implementation.
3 |
4 | # Main features
5 |
6 | * Support for sending and receiving CAN 2.0B data frames. Support for
7 | both standard headers (11-bit ids) and extended headers (29-bit
8 | ids).
9 |
10 | * Support for bus speeds up to 1Mbit/s.
11 |
12 | * Interoperates with other CAN bus implementations. A bus may consist
13 | of one or more can2040 nodes along with non-can2040 nodes.
14 |
15 | * The implementation uses one rp2040/rp2350 PIO hardware block. A
16 | single rp2040 chip may have two separate CAN bus interfaces by using
17 | both of its PIO blocks. A single rp2350 chip may have three
18 | separate CAN bus interfaces.
19 |
20 | * Works with standard CAN bus transceivers. On the rp2040, any two
21 | gpio pins may be used for the "can rx" and "can tx" wires. On the
22 | rp2350, any two gpio pins from GPIO0 to GPIO31 or any two pins from
23 | GPIO16 to GPIO47 may be used.
24 |
25 | # Protocol details
26 |
27 | This section provides some low-level details on can2040's
28 | implementation of the CAN bus protocol. This section is targeted at
29 | CAN bus experts interested in implementation details.
30 |
31 | * Supports clock synchronization for bit timing. That is, the
32 | sampling time is resynchronized on each passive to dominant bit
33 | transition.
34 |
35 | * Supports verification of SOF (start-of-frame), header, data, CRC,
36 | ack, and EOF (end-of-frame) portions of each frame on the CAN bus.
37 |
38 | * Will inject an ack bit after verification of message CRC when
39 | receiving a message.
40 |
41 | * Transmissions will perform "line arbitration". That is, lower
42 | priority transmissions (as based on message id) will yield the bus
43 | to higher priority messages. In addition, the start of
44 | transmissions will be aligned to the SOF bit of other transmitters
45 | for proper bit timing during line arbitration.
46 |
47 | * Support for automatic retransmissions. If a transmission does not
48 | complete successfully (for example, due to an error, lack of
49 | acknowledgment, or interrupted by a higher priority message) then
50 | it will be automatically retransmitted at the next opportunity.
51 |
52 | * Supports sending and receiving "remote frames".
53 |
54 | * Support for receiving "overload frames" (they will successfully
55 | delay transmission of messages). The can2040 code does not transmit
56 | "overload frames".
57 |
58 | * Support for receiving "error frames" (they will halt an active
59 | transmission). However, can2040 does not transmit "error frames".
60 |
61 | There are some known limitations with CAN bus error handling:
62 |
63 | * The CAN bus specification defines three error handling states:
64 | "error active" (ie, normal state), "error passive", and "bus off".
65 | Automatic transition between these states is not implemented. The
66 | can2040 code does not transmit "error frames". The can2040 code
67 | will not automatically enter a "bus off" state. In this regard, the
68 | can2040 code may be thought of as always being in the "error
69 | passive" state.
70 |
71 | # Software utilization
72 |
73 | The can2040 system is a software CAN bus implementation. It utilizes
74 | the rp2040/rp2350 PIO device as well as processing time on one of the
75 | rp2040/rp2350 ARM cores.
76 |
77 | One may dedicate an ARM core to can2040. It is also possible for
78 | can2040 to share an ARM core with application code. This section is
79 | targeted at software developers interested in understanding the
80 | software overhead of can2040 when sharing an ARM core.
81 |
82 | * The ARM core processing time is dependent on the amount of bus
83 | traffic, even if that bus traffic is not intended for the node. It
84 | is expected that a fully saturated CAN bus at the fastest supported
85 | rate of 1Mbit/s may use up to ~25% of one of the two rp2040 ARM
86 | cores (when the ARM core is running at 125Mhz). The same rate on an
87 | rp2350 is expected to use up to ~15% of one ARM core (when running
88 | at 150Mhz). A slower CAN bus speed would have a lower worst case
89 | processing time (for example, a bus speed of 500kbit/s is expected
90 | to have half the worst case processing time of a 1Mbit/s bus). A
91 | CAN bus that is idle does not consume any ARM core processing time.
92 |
93 | * The can2040 code requires low ARM core "irq latency" for proper
94 | functionality. If an ARM core is shared with both application code
95 | and can2040, and that application code disables irqs, has high
96 | priority irqs that preempt the can2040 irq handler, or takes similar
97 | actions that increase irq latency then it may impact can2040.
98 |
99 | It is desirable to keep application irq latency low. The following
100 | paragraphs provide some guidance on what may happen if irq latency
101 | exceeds certain thresholds. The "bit time" refers to the amount of
102 | time it takes to transmit one bit on the CAN bus. It is dependent
103 | on the CAN bus speed (for example, a bus frequency of 500000 would
104 | have a bit time of 2 microseconds).
105 |
106 | Above ~3 bit times of irq latency: After successfully transmitting a
107 | message, the can2040 code may not have sufficient time to schedule
108 | the next transmission before another node starts a transmission of
109 | lower priority. As a result, back-to-back high-priority transmits
110 | may be delayed access to a highly contended bus. That is, even if
111 | the node has many high-priority messages it may only get access to
112 | the bus on every other message.
113 |
114 | Above ~7 bit times: The code may not have sufficient time to
115 | schedule an acknowledgment for a received message, and/or the code
116 | may not have sufficient time to schedule a high-priority
117 | transmission before another node starts a transmission of lower
118 | priority. This may result in message retransmissions and it may
119 | result in a high-priority message from the node being delayed during
120 | periods of high bus contention.
121 |
122 | Above ~80 bit times: The code may not have sufficient time to read
123 | all bytes before the "PIO FIFO queue" overflows. As a result,
124 | received messages on the CAN bus sent to the node may be permanently
125 | lost and messages transmitted from the node may be transmitted
126 | multiple times.
127 |
128 | The can2040 irq handler itself may introduce some irq latency (to
129 | itself and other irq handlers of equal or lower priority). With an
130 | ARM core running at 125Mhz, it is expected that each can2040 irq
131 | will typically take between 1 to 3 microseconds. (An rp2040/rp2350
132 | instruction flash cache miss and/or higher priority irqs may
133 | increase this time.)
134 |
--------------------------------------------------------------------------------
/docs/Releases.md:
--------------------------------------------------------------------------------
1 | History of can2040 releases.
2 |
3 | # v1.7.0
4 |
5 | Available on 20250102. Major features in this release:
6 | * Support for rp2350 chips. The can2040 code can now run on either
7 | rp2040 chips or rp2350 chips.
8 | * Support for v2.0.0 of the pico-sdk.
9 |
10 | # v1.6.0
11 |
12 | Available on 20231001. Major features in this release:
13 | * Added a new `can2040_stop()` API function. This function can be used
14 | to either temporary pause or permanently halt the processing of CAN
15 | bus messages. It is effectively the inverse of the existing
16 | `can2040_start()` function.
17 | * Added a new `can2040_get_statistics()` API function. This can be
18 | used to monitor the low-level performance of the CAN bus interface.
19 | In particular it can monitor the number of can2040 parse errors and
20 | retransmit attempts.
21 |
22 | # v1.5.0
23 |
24 | Available on 20230520. Major features in this release:
25 | * Message transmit bit timing will now only synchronize to faster
26 | transmitters (as is recommended by the CAN bus specification). This
27 | avoids poor transmit timing due to delays between CAN Tx and CAN Rx
28 | signals.
29 | * Improved multi-core support in `can2040_transmit()`. This function
30 | can now be called on one core while the other core may be running
31 | `can2040_pio_irq_handler()`.
32 | * Fixed a possible "transmit hang" that could occur if a transmit
33 | fails due to reception of an error frame.
34 |
35 | # v1.4.0
36 |
37 | Available on 20221121. Major features in this release:
38 | * Reduce scheduling latency of new transmit requests that occur while
39 | parsing the end of an incoming message.
40 | * Reduce ARM core processing load by reading 10 bits at a time from
41 | the PIO.
42 | * Fixed message retransmit handling when no other node on the bus is
43 | transmitting.
44 | * Fixed selection of PIO1 hardware block.
45 | * Assorted documentation and internal code cleanups.
46 |
47 | The v1.4.0 release was retroactively tagged on 20230313.
48 |
49 | ## v1.4.1
50 |
51 | Available on 20230314. This is a bug fix only release:
52 | * Fixed error that could cause a "duplicate ack" to be generated in
53 | rare situations.
54 |
55 | # v1.3.0
56 |
57 | Available on 20220725. Major features in this release:
58 | * Reduce scheduling latency for transmissions immediately after
59 | receiving a message.
60 | * Assorted documentation and internal code cleanups.
61 |
62 | The v1.3.0 release was retroactively tagged on 20230313.
63 |
64 | # v0.2.0
65 |
66 | Available on 20220630. Major features in this release:
67 | * Initial API and user documentation.
68 | * Support "extended" and "remote" frames.
69 | * Increase PIO frequency to improve receive message sample timing.
70 | * No need to require DMA hardware. This simplifies the user-facing API.
71 | * Improved handling of invalid data found during message parsing.
72 | * Assorted ARM CPU processing optimizations.
73 | * Assorted internal code cleanups.
74 |
75 | The v0.2.0 release was retroactively tagged on 20230313.
76 |
77 | # v0.1.0
78 |
79 | Available on 20220602. Major features in this release:
80 | * Initial code release.
81 | * Basic support for sending and receiving CAN 2.0B data frames.
82 |
83 | The v0.1.0 release was retroactively tagged on 20230313.
84 |
--------------------------------------------------------------------------------
/docs/Tools.md:
--------------------------------------------------------------------------------
1 | This document describes some available tools that may be useful for
2 | testing and debugging the can2040 code. These tools may also
3 | facilitate development and may be useful as coding examples.
4 |
5 | # Klipper
6 |
7 | The [Klipper](https://www.klipper3d.org/) code utilizes can2040 for
8 | micro-controller CAN bus communication on rp2040/rp2350 chips.
9 |
10 | Klipper can also be compiled in a [USB to CAN bus bridge
11 | mode](https://www.klipper3d.org/CANBUS.html#usb-to-can-bus-bridge-mode)
12 | so that an rp2040/rp2350 device appears as a standard Linux USB to CAN
13 | bus adapter (using the "gs_usb" Linux driver). Compiling the Klipper
14 | micro-controller code in this mode may be useful for CAN bus
15 | diagnostics even when not using Klipper. See the [Klipper
16 | installation](https://www.klipper3d.org/Installation.html)
17 | instructions for the full installation instructions. Briefly, on a
18 | Raspberry Pi computer the installation involves:
19 | 1. Download the Klipper code
20 | (`git clone https://github.com/Klipper3d/klipper`).
21 | 2. Install compiler tools
22 | (`sudo apt-get update && sudo apt-get install build-essential libncurses-dev libusb-dev libnewlib-arm-none-eabi gcc-arm-none-eabi binutils-arm-none-eabi libusb-1.0 pkg-config`).
23 | 3. Configure the micro-controller software (`make menuconfig`).
24 | Select "Enable extra low-level configuration options", select
25 | "Raspberry Pi RP2040/RP235x" as the micro-controller, select "No
26 | bootloader", select "USB to CAN bus bridge", set the appropriate
27 | gpio pins for CAN RX and CAN TX, and set the desired CAN bus
28 | frequency.
29 | 4. Build the micro-controller software (`make`).
30 | 5. Place the rp2040/rp2350 micro-controller in bootloader mode and
31 | flash the software (`make flash FLASH_DEVICE=2e8a:0003`).
32 |
33 | Once the Klipper micro-controller code is running on the rp2040/rp2350
34 | it is possible to use the Linux
35 | [can-utils](https://github.com/linux-can/can-utils) tools. Briefly:
36 | 1. Install the can-utils package
37 | (`sudo apt-get update && sudo apt-get install can-utils`).
38 | 2. Bring up the "can0" Linux interface
39 | (eg, `sudo ip link set can0 up type can bitrate 1000000`). Note
40 | that Klipper currently uses the CAN bus frequency set during "make
41 | menuconfig" and the value set in Linux is ignored.
42 | 3. In one window run the candump utility to show all packets read by
43 | the interface (eg, `candump -t z -Ddex can0,#FFFFFFFF`).
44 | 4. In another window, send packets on the CAN bus
45 | (eg, `cansend can0 123#121212121212`).
46 |
47 | # Katapult
48 |
49 | The [Katapult](https://github.com/Arksine/Katapult) code implements a
50 | cross-platform bootloader that supports flashing an rp2040
51 | micro-controller over CAN bus. It utilizes can2040 on rp2040 chips.
52 |
53 | # Testing CAN bus
54 |
55 | Note that can2040 (and CAN bus in general) requires a functional
56 | hardware bus for proper message generation. At a minimum, can2040
57 | requires a functioning transceiver, functioning "CAN H" and "CAN L"
58 | wiring, two 120 Ohm resistors on that wiring, at least one additional
59 | CAN bus enabled chip with its own transceiver, and all chips much be
60 | configured with the same CAN bus frequency. If any of the above
61 | hardware is missing or not properly connected/configured then the bus
62 | will not function correctly; not even for debugging purposes.
63 |
64 | # Testing with Raspberry Pi Pico board
65 |
66 | It is possible to use a Raspberry Pi Pico board with a CAN bus
67 | transceiver board for testing. The following picture shows an example
68 | wiring with a "Waveshare SN65HVD230 CAN Board":
69 |
70 | 
71 |
72 | In the above picture, 3.3V on the transceiver board is wired to 3.3V
73 | on the Pico, GND is wired to GND, CAN Rx is wired to GPIO4, and CAN Tx
74 | is wired to GPIO5. (Note that the "Waveshare SN65HVD230 CAN Board"
75 | has a builtin 120 Ohm resistor between the CANH and CANL wires which
76 | is not easy to remove.)
77 |
78 | # Sigrok logic analyzer
79 |
80 | The [Sigrok Pulseview](https://sigrok.org/wiki/PulseView) software
81 | along with a low-cost logic analyzer can be useful for diagnosing CAN
82 | bus signaling.
83 |
84 | One can often find "USB logic analyzers" for under $15 (US pricing as
85 | of 2023). These devices are often listed as "Saleae logic clones" or
86 | as "24MHz 8 channel USB logic analyzers".
87 |
88 | 
89 |
90 | The above picture was taken while using pulseview with a "Saleae
91 | clone" logic analyzer. The Sigrok and pulseview software was
92 | installed on a desktop machine (also install the "fx2lafw" firmware if
93 | that is packaged separately). The CH0 pin on the logic analyzer was
94 | routed to the rp2040 CAN Rx line, the CH1 pin was wired to the CAN Tx
95 | pin, and GND was wired to GND. Pulseview was configured to only
96 | display the D0 and D1 lines (red "probe" icon center top toolbar).
97 | The number of samples was set to 5 million (top toolbar) and the
98 | sample rate was set to 24Mhz (top toolbar). The CAN decoder was added
99 | (yellow and green "bubble icon" right top toolbar). The D0 channel
100 | was labeled as RX and set to trigger on a falling edge (click on black
101 | D0 label at left). The D1 channel was labeled as TX (click on brown
102 | D1 label at left). The CAN decoder was configured for 1Mbit rate
103 | (click on green CAN label at left). The CAN decoder was moved to the
104 | top of the display (click and drag green CAN label). Finally, the
105 | capture was started (click "Run" at top left) and a packet was
106 | transmitted on the CAN bus (`cansend can0 123#121212121212`).
107 |
108 | The logic analyzer can provide an independent tool for capturing
109 | packets and verifying bit timing.
110 |
--------------------------------------------------------------------------------
/docs/img/pico-wiring.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KevinOConnor/can2040/bcfadf84bf248f662b20676494df7757cfc55cb0/docs/img/pico-wiring.jpg
--------------------------------------------------------------------------------
/docs/img/pulseview-canbus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KevinOConnor/can2040/bcfadf84bf248f662b20676494df7757cfc55cb0/docs/img/pulseview-canbus.png
--------------------------------------------------------------------------------
/example/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Demo cmake rules for the can2040 example using Pico SDK
2 | #
3 | # This is a minimal set of build rules. See the PICO SDK
4 | # documentation for more information. In brief, from a Unix
5 | # command-line one would issue commands similar to:
6 | # mkdir build
7 | # cd build
8 | # cmake -D PICO_BOARD=pico ..
9 | # make
10 | # Then flash the resulting canexample.uf2 to the target board.
11 |
12 | cmake_minimum_required(VERSION 3.13)
13 |
14 | # Download SDK from git (or "cmake -D PICO_SDK_PATH=/some/path ..." to avoid)
15 | set(PICO_SDK_FETCH_FROM_GIT on)
16 |
17 | include(pico_sdk_import.cmake)
18 |
19 | project(can2040_example)
20 |
21 | pico_sdk_init()
22 |
23 | add_executable(canexample
24 | canexample.c
25 | ../src/can2040.c
26 | )
27 |
28 | pico_set_binary_type(canexample copy_to_ram)
29 | target_link_libraries(canexample pico_stdlib)
30 | pico_enable_stdio_usb(canexample 1)
31 | pico_enable_stdio_uart(canexample 0)
32 |
33 | pico_add_extra_outputs(canexample)
34 |
--------------------------------------------------------------------------------
/example/canbuild.docker:
--------------------------------------------------------------------------------
1 | # This dockerfile is a reference for building and running a container
2 | # utilizing the Raspberry Pi pico-sdk.
3 | #
4 | # Typically one would build the container with something like:
5 | # docker build -t canbuild -f example/canbuild.docker
6 | # And then one could generate the canexample.uf2 file with something like:
7 | # mkdir build
8 | # docker run --rm -it -v ./example:/root/example -v ./src:/root/src -v ./build:/root/build -w /root/build localhost/canbuild /bin/bash -c 'cmake -D PICO_SDK_PATH=../pico-sdk -D PICO_BOARD=pico ../example && make'
9 |
10 | FROM ubuntu:22.04 as base
11 |
12 | ENV DEBIAN_FRONTEND=noninteractive
13 |
14 | RUN apt update && apt install -y \
15 | cmake python3 build-essential gcc-arm-none-eabi \
16 | libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib \
17 | git
18 |
19 | RUN cd ~ && git clone --depth 1 --branch 2.1.1 https://github.com/raspberrypi/pico-sdk.git && cd pico-sdk && git submodule update --init
20 |
--------------------------------------------------------------------------------
/example/canexample.c:
--------------------------------------------------------------------------------
1 | // This is a simple example program using can2040 and the PICO SDK.
2 | //
3 | // See the CMakeLists.txt file for information on compiling.
4 |
5 | #include
6 | #include
7 |
8 | #include "../src/can2040.h"
9 |
10 | // Simple example of irq safe queue (this is not multi-core safe)
11 | #define QUEUE_SIZE 128 // Must be power of 2
12 | static struct {
13 | uint32_t pull_pos;
14 | volatile uint32_t push_pos;
15 | struct can2040_msg queue[QUEUE_SIZE];
16 | } MessageQueue;
17 |
18 | // Internal storage for can2040 module
19 | static struct can2040 cbus;
20 |
21 | // Main canbus callback (called from irq handler)
22 | static void
23 | can2040_cb(struct can2040 *cd, uint32_t notify, struct can2040_msg *msg)
24 | {
25 | if (notify == CAN2040_NOTIFY_RX) {
26 | // Example message filter
27 | uint32_t id = msg->id;
28 | if (id < 0x101 || id > 0x201)
29 | return;
30 |
31 | // Add to queue
32 | uint32_t push_pos = MessageQueue.push_pos;
33 | uint32_t pull_pos = MessageQueue.pull_pos;
34 | if (push_pos + 1 == pull_pos)
35 | // No space in queue
36 | return;
37 | MessageQueue.queue[push_pos % QUEUE_SIZE] = *msg;
38 | MessageQueue.push_pos = push_pos + 1;
39 | }
40 | }
41 |
42 | // PIO interrupt handler
43 | static void
44 | PIOx_IRQHandler(void)
45 | {
46 | can2040_pio_irq_handler(&cbus);
47 | }
48 |
49 | // Initialize the can2040 module
50 | void
51 | canbus_setup(void)
52 | {
53 | uint32_t pio_num = 0;
54 | uint32_t sys_clock = SYS_CLK_HZ, bitrate = 500000;
55 | uint32_t gpio_rx = 4, gpio_tx = 5;
56 |
57 | // Setup canbus
58 | can2040_setup(&cbus, pio_num);
59 | can2040_callback_config(&cbus, can2040_cb);
60 |
61 | // Enable irqs
62 | irq_set_exclusive_handler(PIO0_IRQ_0, PIOx_IRQHandler);
63 | irq_set_priority(PIO0_IRQ_0, 1);
64 | irq_set_enabled(PIO0_IRQ_0, 1);
65 |
66 | // Start canbus
67 | can2040_start(&cbus, sys_clock, bitrate, gpio_rx, gpio_tx);
68 | }
69 |
70 | int
71 | main(void)
72 | {
73 | stdio_init_all();
74 | canbus_setup();
75 |
76 | // Main loop
77 | for (;;) {
78 | uint32_t push_pos = MessageQueue.push_pos;
79 | uint32_t pull_pos = MessageQueue.pull_pos;
80 | if (push_pos == pull_pos)
81 | // No new messages read.
82 | continue;
83 |
84 | // Pop message from local receive queue
85 | struct can2040_msg *qmsg = &MessageQueue.queue[pull_pos % QUEUE_SIZE];
86 | struct can2040_msg msg = *qmsg;
87 | MessageQueue.pull_pos++;
88 |
89 | // Report message found on local receive queue
90 | printf("msg: id=0x%x dlc=%d data=%02x%02x%02x%02x%02x%02x%02x%02x\n",
91 | msg.id, msg.dlc, msg.data[0], msg.data[1], msg.data[2],
92 | msg.data[3], msg.data[4], msg.data[5], msg.data[6], msg.data[7]);
93 |
94 | // Demo of message transmit
95 | if (msg.id == 0x101) {
96 | struct can2040_msg tmsg;
97 | tmsg.id = 0x102;
98 | tmsg.dlc = 8;
99 | tmsg.data32[0] = 0xabcd;
100 | tmsg.data32[1] = msg.data32[0];
101 | int sts = can2040_transmit(&cbus, &tmsg);
102 | printf("Sent message (status=%d)\n", sts);
103 | }
104 | }
105 |
106 | return 0;
107 | }
108 |
--------------------------------------------------------------------------------
/example/pico_sdk_import.cmake:
--------------------------------------------------------------------------------
1 | # This is a copy of /external/pico_sdk_import.cmake
2 |
3 | # This can be dropped into an external project to help locate this SDK
4 | # It should be include()ed prior to project()
5 |
6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
9 | endif ()
10 |
11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
14 | endif ()
15 |
16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
19 | endif ()
20 |
21 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
22 | set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
23 | message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
24 | endif ()
25 |
26 | if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
27 | set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
28 | message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
29 | endif()
30 |
31 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
32 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
33 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
34 | set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK")
35 |
36 | if (NOT PICO_SDK_PATH)
37 | if (PICO_SDK_FETCH_FROM_GIT)
38 | include(FetchContent)
39 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
40 | if (PICO_SDK_FETCH_FROM_GIT_PATH)
41 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
42 | endif ()
43 | # GIT_SUBMODULES_RECURSE was added in 3.17
44 | if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
45 | FetchContent_Declare(
46 | pico_sdk
47 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
48 | GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
49 | GIT_SUBMODULES_RECURSE FALSE
50 | )
51 | else ()
52 | FetchContent_Declare(
53 | pico_sdk
54 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
55 | GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
56 | )
57 | endif ()
58 |
59 | if (NOT pico_sdk)
60 | message("Downloading Raspberry Pi Pico SDK")
61 | FetchContent_Populate(pico_sdk)
62 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
63 | endif ()
64 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
65 | else ()
66 | message(FATAL_ERROR
67 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
68 | )
69 | endif ()
70 | endif ()
71 |
72 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
73 | if (NOT EXISTS ${PICO_SDK_PATH})
74 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
75 | endif ()
76 |
77 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
78 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
79 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
80 | endif ()
81 |
82 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
83 |
84 | include(${PICO_SDK_INIT_CMAKE_FILE})
85 |
--------------------------------------------------------------------------------
/pio/README.md:
--------------------------------------------------------------------------------
1 | This directory contains reference information on can2040's usage of
2 | the Raspberry Pi rp2040 "Programmable Input/Output block" (PIO).
3 |
4 | One may use the can2040 code without needing to build or utilize the
5 | files in this directory.
6 |
7 | This information here may be useful for those interested in the
8 | internal behavior of the can2040 implementation.
9 |
--------------------------------------------------------------------------------
/pio/can2040.pio:
--------------------------------------------------------------------------------
1 | // Reference code for rp2040 PIO handlers
2 | //
3 | // Copyright (C) 2022 Kevin O'Connor
4 | //
5 | // This file may be distributed under the terms of the GNU GPLv3 license.
6 |
7 | .program can2040
8 |
9 | // This is the main PIO code for the can2040 CANbus software. The
10 | // code is convoluted due to space constraints of the PIO (a max of 32
11 | // instructions).
12 |
13 | // This implementation is designed to run at 32 times the bitrate.
14 | // The "cp=" comments in the code indicate the "clock phase" - which
15 | // ranges from 0 to 31 (32 is 0 again). At "cp=0" a one to zero edge
16 | // is first detected, at "cp=26" is the sampling point, and "cp=31"
17 | // output changes are made (so that they are observed by "cp=32").
18 |
19 | // State machine "sync" code - clock and start/end of message signaling
20 | sync_recessive_edge:
21 | jmp y--, sync_scan_edge ; cp=31,33,35,37
22 | jmp x--, sync_signal_sample ; cp=6
23 | public sync_found_end_of_message:
24 | set x, 9 ; cp=7
25 | sync_loop_end_of_message:
26 | jmp pin sync_check_idle
27 | public sync_signal_start:
28 | irq set 0
29 | sync_scan_edge:
30 | jmp pin sync_recessive_edge ; cp=30,32,34,36
31 | public sync_entry:
32 | irq clear 0 ; cp=1
33 | sync_got_dominant:
34 | set x, 9 [4] ; cp=2
35 | sync_signal_sample:
36 | set y, 3 [16] ; cp=7
37 | irq set 4 [1] ; cp=24
38 | jmp pin sync_scan_edge [3] ; cp=26
39 | jmp sync_got_dominant [3] ; cp=30
40 | sync_check_idle:
41 | jmp x-- sync_loop_end_of_message
42 | public sync_end:
43 | ;jmp sync_signal_start ; wrap based jump
44 |
45 | // State machine "rx" code - forward data to cpu
46 | public shared_rx_read:
47 | wait 1 irq 4
48 | in pins, 1 ; cp=26
49 | public shared_rx_end:
50 | ;jmp shared_rx_read ; wrap based jump
51 |
52 | // State machine "match" code - raise "matched" signal on a raw bitstream match
53 | mov y, isr ; cp=27
54 | jmp x!=y match_load_next [1]; cp=28
55 | match_signal:
56 | irq set 2 ; cp=30
57 | public match_load_next:
58 | in osr, 11 ; load next_counter and bits into isr
59 | in y, 20
60 | mov y, osr
61 | match_check_next:
62 | pull noblock ; reload target_compare into x
63 | mov x, osr
64 | jmp y-- f2 ; setup next_counter
65 | public tx_conflict:
66 | f2:mov osr, y
67 | public match_end:
68 | ;jmp shared_rx_read ; wrap based jump
69 |
70 | // State machine "tx" code - write messages to bus
71 | public tx_got_recessive:
72 | out x, 1 ; cp=27
73 | jmp pin tx_align ; cp=28
74 | public tx_write_pin:
75 | mov pins, x [24] ; cp=31
76 | jmp pin tx_got_recessive [2]; cp=24
77 | jmp x-- tx_conflict ; cp=27 On conflict, spin forever on dummy insn
78 | out x, 1 ; cp=28
79 | tx_align:
80 | jmp tx_write_pin [1] ; cp=29
81 |
82 |
83 | //
84 | // Setup code (reference only)
85 | //
86 |
87 | // Setup for "sync" state machine
88 | .program sm_sync_setup
89 | set pindirs, 0
90 | // CPU pushes 105 into tx fifo - to set OSR for alternative slow start mode
91 | pull
92 | ;jmp sync_got_dominant
93 |
94 | // Alternate code for sync_found_end_of_message when slow start needed
95 | .program sm_sync_alt_slow_start
96 | mov x, osr [1]
97 |
98 | // Setup for "rx" state machine
99 | .program sm_rx_setup
100 | ;jmp shared_rx_read
101 |
102 | // Setup for "match" state machine
103 | .program sm_match_setup
104 | set y, 0
105 | mov osr, y
106 | mov x, !y
107 | ;jmp match_load_next
108 |
109 | // Setup for "tx" state machine
110 | .program sm_tx_setup
111 | set pins, 1
112 | set pindirs, 1
113 |
114 | // Transmit sequence for "tx" state machine
115 | .program sm_tx_transmit
116 | // CPU first disables state machine execution
117 | // CPU clears irq 2 and irq 3
118 | // CPU then loads tx fifos with full (bitstuffed) message
119 | set pins, 1
120 | out x, 1
121 | ;jmp tx_write_pin
122 | wait 1 irq 0
123 | // CPU then starts state machine execution
124 |
125 | // Transmit sequence for "tx" state machine ack injection
126 | .program sm_tx_ack
127 | // CPU first disables state machine execution
128 | // CPU clears irq 2 and irq 3
129 | // CPU changes instruction at tx_got_recessive from "out x, 1" to:
130 | irq wait 3
131 | // CPU then loads tx fifo with ack (single off bit)
132 | set pins, 1
133 | out x, 1
134 | ;jmp tx_write_pin
135 | wait 1 irq 2
136 | // CPU then starts state machine execution
137 | // CPU then loads match fifo with CRC/position sequence to check
138 |
139 |
140 | //
141 | // Reference "sync" state machine without code size reduction hacks
142 | //
143 |
144 | .program reference_sync_sm
145 |
146 | sync_got_dominant:
147 | set x, 9
148 | jmp sync_signal_sample
149 |
150 | sync_signal_sample:
151 | irq set 4
152 | jmp pin sync_scan_edge
153 | jmp sync_got_dominant
154 |
155 | sync_scan_edge:
156 | set y, 3
157 | sync_loop_scan_edge:
158 | jmp pin sync_recessive_edge
159 | jmp sync_got_dominant
160 | sync_recessive_edge:
161 | jmp y--, sync_loop_scan_edge
162 | jmp x--, sync_signal_sample
163 | jmp sync_found_end_of_message
164 |
165 | sync_found_end_of_message:
166 | set x, 8
167 | sync_loop_end_of_message:
168 | jmp pin sync_check_idle
169 | jmp sync_signal_start
170 | sync_check_idle:
171 | jmp x-- sync_loop_end_of_message
172 | jmp sync_found_idle
173 |
174 | sync_found_idle:
175 | irq set 0
176 | sync_loop_idle:
177 | jmp pin sync_loop_idle
178 | jmp sync_signal_start
179 |
180 | sync_signal_start:
181 | irq set 0
182 | irq clear 0
183 | jmp sync_got_dominant
184 |
--------------------------------------------------------------------------------
/pio/pioasm.docker:
--------------------------------------------------------------------------------
1 | # This dockerfile is a reference for building and running a container
2 | # for the Raspberry Pi pico "pioasm" utility.
3 | #
4 | # Typically one would build the container with something like:
5 | # docker build -t pioasm -f pio/pioasm.docker
6 | # And then one could assemble the can2040.pio file with something like:
7 | # docker run --rm -it -v ./pio:/project localhost/pioasm /project/can2040.pio
8 |
9 | FROM ubuntu:22.04 as base
10 |
11 | ENV DEBIAN_FRONTEND=noninteractive
12 |
13 | RUN apt update && apt install -y \
14 | build-essential \
15 | cmake \
16 | git
17 |
18 | RUN cd ~ && git clone --depth 1 --branch 2.1.1 https://github.com/raspberrypi/pico-sdk.git
19 |
20 | RUN mkdir ~/piobuild && cd ~/piobuild \
21 | && cmake ~/pico-sdk/tools/pioasm \
22 | && make
23 |
24 | ENTRYPOINT ["/root/piobuild/pioasm"]
25 |
--------------------------------------------------------------------------------
/scripts/bitstuf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Tool for testing bitstuffing implementations
3 | #
4 | # Copyright (C) 2022-2024 Kevin O'Connor
5 | #
6 | # This file may be distributed under the terms of the GNU GPLv3 license.
7 | import sys
8 |
9 | TESTBITS=20
10 |
11 | def report(msg):
12 | sys.stderr.write("\n" + msg + "\n")
13 |
14 | def clz(v):
15 | v &= 0xffffffff
16 | return 32 - v.bit_length()
17 |
18 | LOOP = UNLOOP = 0
19 |
20 | def bitstuf(b, num_bits):
21 | global LOOP
22 | edges = b ^ (b >> 1)
23 | count = num_bits
24 | i = num_bits-1
25 | while i >= 0:
26 | LOOP += 1
27 | if not ((edges >> i) & 0xf):
28 | mask = (1 << (i + 1)) - 1
29 | low = b & mask
30 | high = (b & ~(mask >> 1)) << 1
31 | b = high ^ low ^ (1 << i)
32 | i -= 3
33 | count += 1
34 | edges = b ^ (b >> 1)
35 | i -= 1
36 | return b, count
37 |
38 | def bitstuf_batch(b, num_bits):
39 | global LOOP
40 | count = num_bits
41 | while 1:
42 | edges = b ^ (b >> 1)
43 | e2 = edges | (edges >> 1)
44 | e4 = e2 | (e2 >> 2)
45 | add_bits = ~e4
46 | try_cnt = num_bits
47 | while 1:
48 | LOOP += 1
49 | try_mask = ((1 << try_cnt) - 1) << (num_bits - try_cnt)
50 | if not add_bits & try_mask:
51 | # No stuff bits needed in try_cnt bits
52 | if try_cnt >= num_bits:
53 | return b, count
54 | num_bits -= try_cnt
55 | try_cnt = (num_bits + 1) // 2
56 | continue
57 | if add_bits & (1 << (num_bits - 1)):
58 | # A stuff bit must be inserted prior to the high bit
59 | low_mask = (1 << num_bits) - 1
60 | low = b & low_mask
61 | high = (b & ~(low_mask >> 1)) << 1
62 | b = high ^ low ^ (1 << (num_bits - 1))
63 | count += 1
64 | if num_bits <= 4:
65 | return b, count
66 | num_bits -= 4
67 | break
68 | # High bit doesn't need stuff bit - accept it, limit try_cnt, retry
69 | num_bits -= 1
70 | try_cnt //= 2
71 |
72 | def bitstuf_clz(b, num_bits):
73 | global LOOP
74 | count = num_bits
75 | while 1:
76 | LOOP += 1
77 | edges = b ^ (b >> 1)
78 | e2 = edges | (edges >> 1)
79 | e4 = e2 | (e2 >> 2)
80 | add_bits = ~e4
81 | mask = (1 << num_bits) - 1
82 | add_masked_bits = add_bits & mask
83 | if not add_masked_bits:
84 | # No more stuff bits needed
85 | return b, count
86 | # Insert a stuff bit
87 | stuff_pos = 1 + 31 - clz(add_masked_bits)
88 | low_mask = (1 << stuff_pos) - 1
89 | low = b & low_mask
90 | high = (b & ~(low_mask >> 1)) << 1
91 | b = high ^ low ^ (1 << (stuff_pos - 1))
92 | count += 1
93 | if stuff_pos <= 4:
94 | return b, count
95 | num_bits = stuff_pos - 4
96 |
97 | def bitunstuf(sb, num_bits):
98 | global UNLOOP
99 | edges = sb ^ (sb >> 1)
100 | unstuffed_bits = 0
101 | cu = TESTBITS
102 | cs = num_bits
103 | while 1:
104 | UNLOOP += 1
105 | if not cu:
106 | # Extracted desired bits
107 | return unstuffed_bits
108 | if not cs:
109 | # Need more data
110 | return -999
111 | cs -= 1
112 | if (edges >> (cs+1)) & 0xf:
113 | # Normal data
114 | cu -= 1
115 | unstuffed_bits |= ((sb >> cs) & 1) << cu
116 | elif ((edges >> cs) & 0x1f) == 0x00:
117 | # Six consecutive bits - a bitstuff error
118 | if (sb >> cs) & 1:
119 | return -cs
120 | return -cs
121 |
122 | def bitunstuf_batch(sb, num_bits):
123 | global UNLOOP
124 | edges = sb ^ (sb >> 1)
125 | e2 = edges | (edges >> 1)
126 | e4 = e2 | (e2 >> 2)
127 | rm_bits = ~e4
128 | unstuffed_bits = 0
129 | cu = TESTBITS
130 | cs = num_bits
131 | while 1:
132 | try_cnt = cu if cu < cs else cs
133 | while 1:
134 | UNLOOP += 1
135 | try_mask = ((1 << try_cnt) - 1) << (cs + 1 - try_cnt)
136 | if not (rm_bits & try_mask):
137 | # No stuff bits in try_cnt bits - copy into unstuffed_bits
138 | cu -= try_cnt
139 | cs -= try_cnt
140 | unstuffed_bits |= ((sb >> cs) & ((1 << try_cnt) - 1)) << cu
141 | if not cu:
142 | # Extracted desired bits
143 | return unstuffed_bits
144 | break
145 | cs -= 1
146 | if rm_bits & (1 << (cs + 1)):
147 | # High bit of try_cnt a stuff bit
148 | if rm_bits & (1 << cs):
149 | # Six consecutive bits - a bitstuff error
150 | if (sb >> cs) & 1:
151 | return -cs
152 | return -cs
153 | break
154 | # High bit not a stuff bit - limit try_cnt and retry
155 | cu -= 1
156 | unstuffed_bits |= ((sb >> cs) & 1) << cu
157 | try_cnt //= 2
158 | if not cs:
159 | # Need more data
160 | return -999
161 |
162 | def bitunstuf_batch_pass4(sb, num_bits):
163 | global UNLOOP
164 | edges = sb ^ (sb >> 1)
165 | e2 = edges | (edges >> 1)
166 | e4 = e2 | (e2 >> 2)
167 | rm_bits = ~e4
168 | unstuffed_bits = 0
169 | cu = TESTBITS
170 | cs = num_bits
171 | try_cnt = cu if cu < cs else cs
172 | while 1:
173 | UNLOOP += 1
174 | pass_cnt = try_cnt
175 | try_mask = ((1 << try_cnt) - 1) << (cs + 1 - try_cnt)
176 | if rm_bits & try_mask:
177 | # There is a stuff bit somewhere in try_cnt
178 | if rm_bits & (1 << cs):
179 | # High bit is a stuff bit
180 | cs -= 1
181 | if rm_bits & (1 << cs):
182 | # Six consecutive bits - a bitstuff error
183 | if (sb >> cs) & 1:
184 | return -cs
185 | return -cs
186 | rem_cnt = cu if cu < cs else cs
187 | pass_cnt = try_cnt = rem_cnt if rem_cnt < 4 else 4
188 | else:
189 | # High bit is not a stuff bit - pass 1, limit try_cnt, retry
190 | pass_cnt = 1
191 | # Copy pass_cnt bits into unstuffed_bits
192 | cu -= pass_cnt
193 | cs -= pass_cnt
194 | unstuffed_bits |= ((sb >> cs) & ((1 << pass_cnt) - 1)) << cu
195 | if not cu:
196 | # Extracted desired bits
197 | return unstuffed_bits
198 | if not cs:
199 | # Need more data
200 | return -999
201 | if pass_cnt >= try_cnt:
202 | try_cnt = cu if cu < cs else cs
203 | else:
204 | try_cnt //= 2
205 |
206 | def bitunstuf_clz(sb, num_bits):
207 | global UNLOOP
208 | edges = sb ^ (sb >> 1)
209 | e2 = edges | (edges >> 1)
210 | e4 = e2 | (e2 >> 2)
211 | rm_bits = ~e4
212 | unstuffed_bits = 0
213 | cu = TESTBITS
214 | cs = num_bits
215 | while 1:
216 | UNLOOP += 1
217 | if not cs:
218 | # Need more data
219 | return -999
220 | try_cnt = cu if cu < cs else cs
221 | try_mask = ((1 << try_cnt) - 1) << (cs + 1 - try_cnt)
222 | rm_masked_bits = rm_bits & try_mask
223 | if not rm_masked_bits:
224 | # No stuff bits in try_cnt bits - copy into unstuffed_bits
225 | cu -= try_cnt
226 | cs -= try_cnt
227 | unstuffed_bits |= ((sb >> cs) & ((1 << try_cnt) - 1)) << cu
228 | if not cu:
229 | # Extracted desired bits
230 | return unstuffed_bits
231 | # Need more data
232 | return -999
233 | # Copy any leading bits prior to stuff bit (may be zero)
234 | copy_cnt = cs - (31 - clz(rm_masked_bits))
235 | cs -= copy_cnt
236 | cu -= copy_cnt
237 | unstuffed_bits |= ((sb >> cs) & ((1 << copy_cnt) - 1)) << cu
238 | # High bit is now a stuff bit - remove it
239 | cs -= 1
240 | if rm_bits & (1 << cs):
241 | # Six consecutive bits - a bitstuff error
242 | if (sb >> cs) & 1:
243 | return -cs
244 | return -cs
245 |
246 | def main():
247 | stuf_func = bitstuf_batch
248 | unstuf_func = bitunstuf_batch
249 | for i in range(1< %s -> %s (%d)"
258 | % (i, format(val, '025b'), format(sv, '025b')
259 | , format(uv, '025b'), sv))
260 | sys.exit(-1)
261 | report("Test completed successfully (avg passes: %.3f stuff, %.3f unstuff)"
262 | % (LOOP / (1<
5 | #
6 | # This file may be distributed under the terms of the GNU GPLv3 license.
7 | import sys
8 |
9 | def report(msg):
10 | sys.stderr.write(msg + "\n")
11 |
12 | # Basic bit-by-bit canbus crc implementation
13 | def crc_bitloop(data):
14 | crc = 0
15 | l = len(data) - 1
16 | val = sum([v << ((l-i)*8) for i, v in enumerate(data)])
17 | count = len(data) * 8
18 | for i in range(count-1, -1, -1):
19 | bit = (val >> i) & 1
20 | if ((crc >> 14) & 1) ^ bit:
21 | crc = (crc << 1) ^ 0x4599
22 | else:
23 | crc = crc << 1
24 | return crc & 0x7fff
25 |
26 | # Simple bit manipulation improvement
27 | def crc_bitloop2(data):
28 | crc = 0
29 | l = len(data) - 1
30 | val = sum([v << ((l-i)*8) for i, v in enumerate(data)])
31 | count = len(data) * 8
32 | for i in range(count-1, -1, -1):
33 | bit = (val >> i) << 15
34 | crc <<= 1
35 | if (crc ^ bit) & (1 << 15):
36 | crc ^= 0x4599
37 | return crc & 0x7fff
38 |
39 | # Byte at a time version
40 | def crc_byteloop(data):
41 | crc = 0
42 | for v in data:
43 | crc ^= v << 7
44 | for i in range(7, -1, -1):
45 | crc <<= 1
46 | if crc & 0x8000:
47 | crc ^= 0x4599
48 | return crc & 0x7fff
49 |
50 | # A 4-bit at a time table lookup version
51 | def crc_4bit_table(table, data):
52 | crc = 0
53 | l = len(data) - 1
54 | val = sum([v << ((l-i)*8) for i, v in enumerate(data)])
55 | count = len(data) * 8
56 | for i in range(count-4, -4, -4):
57 | pos = ((crc >> 11) ^ (val >> i)) & 0x0f
58 | crc = (crc << 4) ^ table[pos]
59 | return crc & 0x7fff
60 |
61 | # A 8-bit at a time table lookup version
62 | def crc_8bit_table(table, data):
63 | crc = 0
64 | for v in data:
65 | crc = (crc << 8) ^ table[((crc >> 7) ^ v) & 0xff]
66 | return crc & 0x7fff
67 |
68 | TESTDATA = b"Some string of data"
69 |
70 | def main():
71 | # Build 4bit table version
72 | bit4_table = [crc_bitloop([i]) for i in range(16)]
73 | print("Table 4bit:", ", ".join(["0x%04x" % i for i in bit4_table]))
74 | # Build 8bit table version
75 | bit8_table = [crc_bitloop([i]) for i in range(256)]
76 | print("Table 8bit:", ",".join(["0x%04x" % i for i in bit8_table]))
77 | # Test versions
78 | for i in range(len(TESTDATA)):
79 | d = TESTDATA[i:]
80 | crc1 = crc_bitloop(d)
81 | crc2 = crc_8bit_table(bit8_table, d)
82 | if crc1 != crc2:
83 | report("Got mismatch on '%s' %02x vs %02x" % (d, crc1, crc2))
84 | sys.exit(-1)
85 | report("Test completed successfully")
86 |
87 | if __name__ == '__main__':
88 | main()
89 |
--------------------------------------------------------------------------------
/src/can2040.c:
--------------------------------------------------------------------------------
1 | // Software CANbus implementation for rp2040
2 | //
3 | // Copyright (C) 2022-2025 Kevin O'Connor
4 | //
5 | // This file may be distributed under the terms of the GNU GPLv3 license.
6 |
7 | #include // uint32_t
8 | #include // memset
9 | #include "can2040.h" // can2040_setup
10 | #include "hardware/regs/dreq.h" // DREQ_PIO0_RX1
11 | #include "hardware/structs/dma.h" // dma_hw
12 | #include "hardware/structs/iobank0.h" // iobank0_hw
13 | #include "hardware/structs/padsbank0.h" // padsbank0_hw
14 | #include "hardware/structs/pio.h" // pio0_hw
15 | #include "hardware/structs/resets.h" // RESETS_RESET_PIO0_BITS
16 |
17 |
18 | /****************************************************************
19 | * rp2040 and low-level helper functions
20 | ****************************************************************/
21 |
22 | // Determine if the target is an rp2350
23 | #ifdef PICO_RP2350
24 | #define IS_RP2350 1
25 | #else
26 | #define IS_RP2350 0
27 | #endif
28 |
29 | // Helper compiler definitions
30 | #define barrier() __asm__ __volatile__("": : :"memory")
31 | #define likely(x) __builtin_expect(!!(x), 1)
32 | #define unlikely(x) __builtin_expect(!!(x), 0)
33 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
34 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
35 | #define __DMB() __asm__ __volatile__("dmb 0xF": : :"memory")
36 |
37 | // Helper functions for writing to "io" memory
38 | static inline void writel(void *addr, uint32_t val) {
39 | barrier();
40 | *(volatile uint32_t *)addr = val;
41 | }
42 | static inline uint32_t readl(const void *addr) {
43 | uint32_t val = *(volatile const uint32_t *)addr;
44 | barrier();
45 | return val;
46 | }
47 |
48 | // rp2040 helper function to clear a hardware reset bit
49 | static void
50 | rp2040_clear_reset(uint32_t reset_bit)
51 | {
52 | if (resets_hw->reset & reset_bit) {
53 | hw_clear_bits(&resets_hw->reset, reset_bit);
54 | while (!(resets_hw->reset_done & reset_bit))
55 | ;
56 | }
57 | }
58 |
59 | // Helper to set the mode and extended function of a pin
60 | static void
61 | rp2040_gpio_peripheral(uint32_t gpio, int func, int pull_up)
62 | {
63 | padsbank0_hw->io[gpio] = (
64 | PADS_BANK0_GPIO0_IE_BITS
65 | | (PADS_BANK0_GPIO0_DRIVE_VALUE_4MA << PADS_BANK0_GPIO0_DRIVE_MSB)
66 | | (pull_up > 0 ? PADS_BANK0_GPIO0_PUE_BITS : 0)
67 | | (pull_up < 0 ? PADS_BANK0_GPIO0_PDE_BITS : 0));
68 | iobank0_hw->io[gpio].ctrl = func << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
69 | }
70 |
71 |
72 | /****************************************************************
73 | * rp2040 PIO support
74 | ****************************************************************/
75 |
76 | #define PIO_CLOCK_PER_BIT 32
77 | #define PIO_RX_WAKE_BITS 10
78 |
79 | #define can2040_offset_sync_found_end_of_message 2u
80 | #define can2040_offset_sync_signal_start 4u
81 | #define can2040_offset_sync_entry 6u
82 | #define can2040_offset_sync_end 13u
83 | #define can2040_offset_shared_rx_read 13u
84 | #define can2040_offset_shared_rx_end 15u
85 | #define can2040_offset_match_load_next 18u
86 | #define can2040_offset_tx_conflict 24u
87 | #define can2040_offset_match_end 25u
88 | #define can2040_offset_tx_got_recessive 25u
89 | #define can2040_offset_tx_write_pin 27u
90 |
91 | static const uint16_t can2040_program_instructions[] = {
92 | 0x0085, // 0: jmp y--, 5
93 | 0x0048, // 1: jmp x--, 8
94 | 0xe029, // 2: set x, 9
95 | 0x00cc, // 3: jmp pin, 12
96 | 0xc000, // 4: irq nowait 0
97 | 0x00c0, // 5: jmp pin, 0
98 | 0xc040, // 6: irq clear 0
99 | 0xe429, // 7: set x, 9 [4]
100 | 0xf043, // 8: set y, 3 [16]
101 | 0xc104, // 9: irq nowait 4 [1]
102 | 0x03c5, // 10: jmp pin, 5 [3]
103 | 0x0307, // 11: jmp 7 [3]
104 | 0x0043, // 12: jmp x--, 3
105 | 0x20c4, // 13: wait 1 irq, 4
106 | 0x4001, // 14: in pins, 1
107 | 0xa046, // 15: mov y, isr
108 | 0x01b2, // 16: jmp x != y, 18 [1]
109 | 0xc002, // 17: irq nowait 2
110 | 0x40eb, // 18: in osr, 11
111 | 0x4054, // 19: in y, 20
112 | 0xa047, // 20: mov y, osr
113 | 0x8080, // 21: pull noblock
114 | 0xa027, // 22: mov x, osr
115 | 0x0098, // 23: jmp y--, 24
116 | 0xa0e2, // 24: mov osr, y
117 | 0x6021, // 25: out x, 1
118 | 0x00df, // 26: jmp pin, 31
119 | 0xb801, // 27: mov pins, x [24]
120 | 0x02d9, // 28: jmp pin, 25 [2]
121 | 0x0058, // 29: jmp x--, 24
122 | 0x6021, // 30: out x, 1
123 | 0x011b, // 31: jmp 27 [1]
124 | };
125 |
126 | // Local names for PIO state machine IRQs
127 | #define SI_MAYTX PIO_IRQ0_INTE_SM0_BITS
128 | #define SI_MATCHED PIO_IRQ0_INTE_SM2_BITS
129 | #define SI_ACKDONE PIO_IRQ0_INTE_SM3_BITS
130 | #define SI_RX_DATA PIO_IRQ0_INTE_SM1_RXNEMPTY_BITS
131 | #define SI_TXPENDING PIO_IRQ0_INTE_SM1_BITS // Misc bit manually forced
132 |
133 | // Local names of the four PIO state machines
134 | enum { SM_SYNC = 0, SM_RX = 1, SM_MATCH = 2, SM_TX = 3 };
135 |
136 | // Return the gpio bank offset (on rp2350 chips)
137 | static uint32_t
138 | pio_gpiobase(struct can2040 *cd)
139 | {
140 | if (!IS_RP2350)
141 | return 0;
142 | return (cd->gpio_rx > 31 || cd->gpio_tx > 31) ? 16 : 0;
143 | }
144 |
145 | // Setup PIO "sync" state machine (state machine 0)
146 | static void
147 | pio_sync_setup(struct can2040 *cd)
148 | {
149 | pio_hw_t *pio_hw = cd->pio_hw;
150 | pio_sm_hw_t *sm = &pio_hw->sm[SM_SYNC];
151 | uint32_t gpio_rx = (cd->gpio_rx - pio_gpiobase(cd)) & 0x1f;
152 | sm->execctrl = (
153 | gpio_rx << PIO_SM0_EXECCTRL_JMP_PIN_LSB
154 | | (can2040_offset_sync_end - 1) << PIO_SM0_EXECCTRL_WRAP_TOP_LSB
155 | | can2040_offset_sync_signal_start << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB);
156 | sm->pinctrl = (
157 | 1 << PIO_SM0_PINCTRL_SET_COUNT_LSB
158 | | gpio_rx << PIO_SM0_PINCTRL_SET_BASE_LSB);
159 | sm->instr = 0xe080; // set pindirs, 0
160 | sm->pinctrl = 0;
161 | pio_hw->txf[SM_SYNC] = 9 + 6 * PIO_CLOCK_PER_BIT / 2;
162 | sm->instr = 0x80a0; // pull block
163 | sm->instr = can2040_offset_sync_entry; // jmp sync_entry
164 | }
165 |
166 | // Setup PIO "rx" state machine (state machine 1)
167 | static void
168 | pio_rx_setup(struct can2040 *cd)
169 | {
170 | pio_hw_t *pio_hw = cd->pio_hw;
171 | pio_sm_hw_t *sm = &pio_hw->sm[SM_RX];
172 | uint32_t gpio_rx = (cd->gpio_rx - pio_gpiobase(cd)) & 0x1f;
173 | sm->execctrl = (
174 | (can2040_offset_shared_rx_end - 1) << PIO_SM0_EXECCTRL_WRAP_TOP_LSB
175 | | can2040_offset_shared_rx_read << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB);
176 | sm->pinctrl = gpio_rx << PIO_SM0_PINCTRL_IN_BASE_LSB;
177 | sm->shiftctrl = 0; // flush fifo on a restart
178 | sm->shiftctrl = (PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS
179 | | PIO_RX_WAKE_BITS << PIO_SM0_SHIFTCTRL_PUSH_THRESH_LSB
180 | | PIO_SM0_SHIFTCTRL_AUTOPUSH_BITS);
181 | sm->instr = can2040_offset_shared_rx_read; // jmp shared_rx_read
182 | }
183 |
184 | // Setup PIO "match" state machine (state machine 2)
185 | static void
186 | pio_match_setup(struct can2040 *cd)
187 | {
188 | pio_hw_t *pio_hw = cd->pio_hw;
189 | pio_sm_hw_t *sm = &pio_hw->sm[SM_MATCH];
190 | sm->execctrl = (
191 | (can2040_offset_match_end - 1) << PIO_SM0_EXECCTRL_WRAP_TOP_LSB
192 | | can2040_offset_shared_rx_read << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB);
193 | uint32_t gpio_rx = (cd->gpio_rx - pio_gpiobase(cd)) & 0x1f;
194 | sm->pinctrl = gpio_rx << PIO_SM0_PINCTRL_IN_BASE_LSB;
195 | sm->shiftctrl = 0;
196 | sm->instr = 0xe040; // set y, 0
197 | sm->instr = 0xa0e2; // mov osr, y
198 | sm->instr = 0xa02a; // mov x, !y
199 | sm->instr = can2040_offset_match_load_next; // jmp match_load_next
200 | }
201 |
202 | // Setup PIO "tx" state machine (state machine 3)
203 | static void
204 | pio_tx_setup(struct can2040 *cd)
205 | {
206 | pio_hw_t *pio_hw = cd->pio_hw;
207 | pio_sm_hw_t *sm = &pio_hw->sm[SM_TX];
208 | uint32_t gpio_rx = (cd->gpio_rx - pio_gpiobase(cd)) & 0x1f;
209 | uint32_t gpio_tx = (cd->gpio_tx - pio_gpiobase(cd)) & 0x1f;
210 | sm->execctrl = (
211 | gpio_rx << PIO_SM0_EXECCTRL_JMP_PIN_LSB
212 | | can2040_offset_tx_conflict << PIO_SM0_EXECCTRL_WRAP_TOP_LSB
213 | | can2040_offset_tx_conflict << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB);
214 | sm->shiftctrl = (PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS
215 | | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS);
216 | sm->pinctrl = (1 << PIO_SM0_PINCTRL_SET_COUNT_LSB
217 | | 1 << PIO_SM0_PINCTRL_OUT_COUNT_LSB
218 | | gpio_tx << PIO_SM0_PINCTRL_SET_BASE_LSB
219 | | gpio_tx << PIO_SM0_PINCTRL_OUT_BASE_LSB);
220 | sm->instr = 0xe001; // set pins, 1
221 | sm->instr = 0xe081; // set pindirs, 1
222 | }
223 |
224 | // Set PIO "sync" machine to signal "may transmit" (sm irq 0) on 11 idle bits
225 | static void
226 | pio_sync_normal_start_signal(struct can2040 *cd)
227 | {
228 | pio_hw_t *pio_hw = cd->pio_hw;
229 | uint32_t eom_idx = can2040_offset_sync_found_end_of_message;
230 | pio_hw->instr_mem[eom_idx] = 0xe12a; // set x, 10 [1]
231 | }
232 |
233 | // Set PIO "sync" machine to signal "may transmit" (sm irq 0) on 17 idle bits
234 | static void
235 | pio_sync_slow_start_signal(struct can2040 *cd)
236 | {
237 | pio_hw_t *pio_hw = cd->pio_hw;
238 | uint32_t eom_idx = can2040_offset_sync_found_end_of_message;
239 | pio_hw->instr_mem[eom_idx] = 0xa127; // mov x, osr [1]
240 | }
241 |
242 | // Test if PIO "rx" state machine has overflowed its fifos
243 | static int
244 | pio_rx_check_stall(struct can2040 *cd)
245 | {
246 | pio_hw_t *pio_hw = cd->pio_hw;
247 | return pio_hw->fdebug & (1 << (PIO_FDEBUG_RXSTALL_LSB + 1));
248 | }
249 |
250 | // Set PIO "match" state machine to raise a "matched" signal on a bit sequence
251 | static void
252 | pio_match_check(struct can2040 *cd, uint32_t match_key)
253 | {
254 | pio_hw_t *pio_hw = cd->pio_hw;
255 | pio_hw->txf[SM_MATCH] = match_key;
256 | }
257 |
258 | // Calculate pos+bits identifier for PIO "match" state machine
259 | static uint32_t
260 | pio_match_calc_key(uint32_t raw_bits, uint32_t rx_bit_pos)
261 | {
262 | return (raw_bits & 0x1fffff) | ((-rx_bit_pos) << 21);
263 | }
264 |
265 | // Cancel any pending checks on PIO "match" state machine
266 | static void
267 | pio_match_clear(struct can2040 *cd)
268 | {
269 | pio_match_check(cd, 0);
270 | }
271 |
272 | // Flush and halt PIO "tx" state machine
273 | static void
274 | pio_tx_reset(struct can2040 *cd)
275 | {
276 | pio_hw_t *pio_hw = cd->pio_hw;
277 | pio_hw->ctrl = 0x07 << PIO_CTRL_SM_ENABLE_LSB;
278 | pio_hw->ctrl = ((0x07 << PIO_CTRL_SM_ENABLE_LSB)
279 | | (0x08 << PIO_CTRL_SM_RESTART_LSB));
280 | pio_hw->irq = (SI_MATCHED | SI_ACKDONE) >> 8; // clear PIO irq flags
281 | // Clear tx fifo
282 | pio_sm_hw_t *sm = &pio_hw->sm[SM_TX];
283 | sm->shiftctrl = 0;
284 | sm->shiftctrl = (PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS
285 | | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS);
286 | }
287 |
288 | // Queue a message for transmission on PIO "tx" state machine
289 | static void
290 | pio_tx_send(struct can2040 *cd, uint32_t *data, uint32_t count)
291 | {
292 | pio_hw_t *pio_hw = cd->pio_hw;
293 | pio_tx_reset(cd);
294 | pio_hw->instr_mem[can2040_offset_tx_got_recessive] = 0x6021; // out x, 1
295 | uint32_t i;
296 | for (i=0; itxf[SM_TX] = data[i];
298 | pio_sm_hw_t *sm = &pio_hw->sm[SM_TX];
299 | sm->instr = 0xe001; // set pins, 1
300 | sm->instr = 0x6021; // out x, 1
301 | sm->instr = can2040_offset_tx_write_pin; // jmp tx_write_pin
302 | sm->instr = 0x20c0; // wait 1 irq, 0
303 | pio_hw->ctrl = 0x0f << PIO_CTRL_SM_ENABLE_LSB;
304 | }
305 |
306 | // Set PIO "tx" state machine to inject an ack after a CRC match
307 | static void
308 | pio_tx_inject_ack(struct can2040 *cd, uint32_t match_key)
309 | {
310 | pio_hw_t *pio_hw = cd->pio_hw;
311 | pio_tx_reset(cd);
312 | pio_hw->instr_mem[can2040_offset_tx_got_recessive] = 0xc023; // irq wait 3
313 | pio_hw->txf[SM_TX] = 0x7fffffff;
314 | pio_sm_hw_t *sm = &pio_hw->sm[SM_TX];
315 | sm->instr = 0xe001; // set pins, 1
316 | sm->instr = 0x6021; // out x, 1
317 | sm->instr = can2040_offset_tx_write_pin; // jmp tx_write_pin
318 | sm->instr = 0x20c2; // wait 1 irq, 2
319 | pio_hw->ctrl = 0x0f << PIO_CTRL_SM_ENABLE_LSB;
320 |
321 | pio_match_check(cd, match_key);
322 | }
323 |
324 | // Did PIO "tx" state machine unexpectedly finish a transmit attempt?
325 | static int
326 | pio_tx_did_fail(struct can2040 *cd)
327 | {
328 | pio_hw_t *pio_hw = cd->pio_hw;
329 | // Check for passive/dominant bit conflict without parser noticing
330 | if (pio_hw->sm[SM_TX].addr == can2040_offset_tx_conflict)
331 | return !(pio_hw->intr & SI_RX_DATA);
332 | // Check for unexpected drain of transmit queue without parser noticing
333 | return (!(pio_hw->flevel & PIO_FLEVEL_TX3_BITS)
334 | && (pio_hw->intr & (SI_MAYTX | SI_RX_DATA)) == SI_MAYTX);
335 | }
336 |
337 | // Enable host irqs for state machine signals
338 | static void
339 | pio_irq_set(struct can2040 *cd, uint32_t sm_irqs)
340 | {
341 | pio_hw_t *pio_hw = cd->pio_hw;
342 | pio_hw->inte0 = sm_irqs | SI_RX_DATA;
343 | }
344 |
345 | // Completely disable host irqs
346 | static void
347 | pio_irq_disable(struct can2040 *cd)
348 | {
349 | pio_hw_t *pio_hw = cd->pio_hw;
350 | pio_hw->inte0 = 0;
351 | }
352 |
353 | // Return current host irq mask
354 | static uint32_t
355 | pio_irq_get(struct can2040 *cd)
356 | {
357 | pio_hw_t *pio_hw = cd->pio_hw;
358 | return pio_hw->inte0;
359 | }
360 |
361 | // Raise the txpending flag
362 | static void
363 | pio_signal_set_txpending(struct can2040 *cd)
364 | {
365 | pio_hw_t *pio_hw = cd->pio_hw;
366 | pio_hw->irq_force = SI_TXPENDING >> 8;
367 | }
368 |
369 | // Clear the txpending flag
370 | static void
371 | pio_signal_clear_txpending(struct can2040 *cd)
372 | {
373 | pio_hw_t *pio_hw = cd->pio_hw;
374 | pio_hw->irq = SI_TXPENDING >> 8;
375 | }
376 |
377 | // Setup PIO state machines
378 | static void
379 | pio_sm_setup(struct can2040 *cd)
380 | {
381 | // Reset state machines
382 | pio_hw_t *pio_hw = cd->pio_hw;
383 | pio_hw->ctrl = PIO_CTRL_SM_RESTART_BITS | PIO_CTRL_CLKDIV_RESTART_BITS;
384 | pio_hw->fdebug = 0xffffffff;
385 | pio_hw->irq = 0xff;
386 | pio_signal_set_txpending(cd);
387 |
388 | // Load pio program
389 | uint32_t i;
390 | for (i=0; iinstr_mem[i] = can2040_program_instructions[i];
392 |
393 | // Set initial state machine state
394 | pio_sync_setup(cd);
395 | pio_rx_setup(cd);
396 | pio_match_setup(cd);
397 | pio_tx_setup(cd);
398 |
399 | // Start state machines
400 | pio_hw->ctrl = 0x07 << PIO_CTRL_SM_ENABLE_LSB;
401 | }
402 |
403 | // Initial setup of gpio pins and PIO state machines
404 | static void
405 | pio_setup(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate)
406 | {
407 | // Configure pio0 clock
408 | uint32_t rb = cd->pio_num ? RESETS_RESET_PIO1_BITS : RESETS_RESET_PIO0_BITS;
409 | #if IS_RP2350
410 | if (cd->pio_num == 2)
411 | rb = RESETS_RESET_PIO2_BITS;
412 | #endif
413 | rp2040_clear_reset(rb);
414 |
415 | // Setup and sync pio state machine clocks
416 | pio_hw_t *pio_hw = cd->pio_hw;
417 | uint32_t div = (256 / PIO_CLOCK_PER_BIT) * sys_clock / bitrate;
418 | int i;
419 | for (i=0; i<4; i++)
420 | pio_hw->sm[i].clkdiv = div << PIO_SM0_CLKDIV_FRAC_LSB;
421 |
422 | // Configure gpiobase (on rp2350)
423 | #if IS_RP2350
424 | pio_hw->gpiobase = pio_gpiobase(cd);
425 | #endif
426 |
427 | // Configure state machines
428 | pio_sm_setup(cd);
429 |
430 | // Map Rx/Tx gpios
431 | uint32_t pio_func = 6 + cd->pio_num;
432 | rp2040_gpio_peripheral(cd->gpio_rx, pio_func, 1);
433 | rp2040_gpio_peripheral(cd->gpio_tx, pio_func, 0);
434 | }
435 |
436 |
437 | /****************************************************************
438 | * CRC calculation
439 | ****************************************************************/
440 |
441 | // Calculated 8-bit crc table (see scripts/crc.py)
442 | static const uint16_t crc_table[256] = {
443 | 0x0000,0x4599,0x4eab,0x0b32,0x58cf,0x1d56,0x1664,0x53fd,0x7407,0x319e,
444 | 0x3aac,0x7f35,0x2cc8,0x6951,0x6263,0x27fa,0x2d97,0x680e,0x633c,0x26a5,
445 | 0x7558,0x30c1,0x3bf3,0x7e6a,0x5990,0x1c09,0x173b,0x52a2,0x015f,0x44c6,
446 | 0x4ff4,0x0a6d,0x5b2e,0x1eb7,0x1585,0x501c,0x03e1,0x4678,0x4d4a,0x08d3,
447 | 0x2f29,0x6ab0,0x6182,0x241b,0x77e6,0x327f,0x394d,0x7cd4,0x76b9,0x3320,
448 | 0x3812,0x7d8b,0x2e76,0x6bef,0x60dd,0x2544,0x02be,0x4727,0x4c15,0x098c,
449 | 0x5a71,0x1fe8,0x14da,0x5143,0x73c5,0x365c,0x3d6e,0x78f7,0x2b0a,0x6e93,
450 | 0x65a1,0x2038,0x07c2,0x425b,0x4969,0x0cf0,0x5f0d,0x1a94,0x11a6,0x543f,
451 | 0x5e52,0x1bcb,0x10f9,0x5560,0x069d,0x4304,0x4836,0x0daf,0x2a55,0x6fcc,
452 | 0x64fe,0x2167,0x729a,0x3703,0x3c31,0x79a8,0x28eb,0x6d72,0x6640,0x23d9,
453 | 0x7024,0x35bd,0x3e8f,0x7b16,0x5cec,0x1975,0x1247,0x57de,0x0423,0x41ba,
454 | 0x4a88,0x0f11,0x057c,0x40e5,0x4bd7,0x0e4e,0x5db3,0x182a,0x1318,0x5681,
455 | 0x717b,0x34e2,0x3fd0,0x7a49,0x29b4,0x6c2d,0x671f,0x2286,0x2213,0x678a,
456 | 0x6cb8,0x2921,0x7adc,0x3f45,0x3477,0x71ee,0x5614,0x138d,0x18bf,0x5d26,
457 | 0x0edb,0x4b42,0x4070,0x05e9,0x0f84,0x4a1d,0x412f,0x04b6,0x574b,0x12d2,
458 | 0x19e0,0x5c79,0x7b83,0x3e1a,0x3528,0x70b1,0x234c,0x66d5,0x6de7,0x287e,
459 | 0x793d,0x3ca4,0x3796,0x720f,0x21f2,0x646b,0x6f59,0x2ac0,0x0d3a,0x48a3,
460 | 0x4391,0x0608,0x55f5,0x106c,0x1b5e,0x5ec7,0x54aa,0x1133,0x1a01,0x5f98,
461 | 0x0c65,0x49fc,0x42ce,0x0757,0x20ad,0x6534,0x6e06,0x2b9f,0x7862,0x3dfb,
462 | 0x36c9,0x7350,0x51d6,0x144f,0x1f7d,0x5ae4,0x0919,0x4c80,0x47b2,0x022b,
463 | 0x25d1,0x6048,0x6b7a,0x2ee3,0x7d1e,0x3887,0x33b5,0x762c,0x7c41,0x39d8,
464 | 0x32ea,0x7773,0x248e,0x6117,0x6a25,0x2fbc,0x0846,0x4ddf,0x46ed,0x0374,
465 | 0x5089,0x1510,0x1e22,0x5bbb,0x0af8,0x4f61,0x4453,0x01ca,0x5237,0x17ae,
466 | 0x1c9c,0x5905,0x7eff,0x3b66,0x3054,0x75cd,0x2630,0x63a9,0x689b,0x2d02,
467 | 0x276f,0x62f6,0x69c4,0x2c5d,0x7fa0,0x3a39,0x310b,0x7492,0x5368,0x16f1,
468 | 0x1dc3,0x585a,0x0ba7,0x4e3e,0x450c,0x0095
469 | };
470 |
471 | // Update a crc with 8 bits of data
472 | static uint32_t
473 | crc_byte(uint32_t crc, uint32_t data)
474 | {
475 | return (crc << 8) ^ crc_table[((crc >> 7) ^ data) & 0xff];
476 | }
477 |
478 | // Update a crc with 8, 16, 24, or 32 bits of data
479 | static inline uint32_t
480 | crc_bytes(uint32_t crc, uint32_t data, uint32_t num)
481 | {
482 | switch (num) {
483 | default: crc = crc_byte(crc, data >> 24); /* FALLTHRU */
484 | case 3: crc = crc_byte(crc, data >> 16); /* FALLTHRU */
485 | case 2: crc = crc_byte(crc, data >> 8); /* FALLTHRU */
486 | case 1: crc = crc_byte(crc, data);
487 | }
488 | return crc;
489 | }
490 |
491 |
492 | /****************************************************************
493 | * Bit unstuffing
494 | ****************************************************************/
495 |
496 | // Add 'count' number of bits from 'data' to the 'bu' unstuffer
497 | static void
498 | unstuf_add_bits(struct can2040_bitunstuffer *bu, uint32_t data, uint32_t count)
499 | {
500 | uint32_t mask = (1 << count) - 1;
501 | bu->stuffed_bits = (bu->stuffed_bits << count) | (data & mask);
502 | bu->count_stuff = count;
503 | }
504 |
505 | // Reset state and set the next desired 'num_bits' unstuffed bits to extract
506 | static void
507 | unstuf_set_count(struct can2040_bitunstuffer *bu, uint32_t num_bits)
508 | {
509 | bu->unstuffed_bits = 0;
510 | bu->count_unstuff = num_bits;
511 | }
512 |
513 | // Clear bitstuffing state (used after crc field to avoid bitstuffing ack field)
514 | static void
515 | unstuf_clear_state(struct can2040_bitunstuffer *bu)
516 | {
517 | uint32_t lb = 1 << bu->count_stuff;
518 | bu->stuffed_bits = (bu->stuffed_bits & (lb - 1)) | (lb << 1);
519 | }
520 |
521 | // Restore raw bitstuffing state (used to undo unstuf_clear_state() )
522 | static void
523 | unstuf_restore_state(struct can2040_bitunstuffer *bu, uint32_t data)
524 | {
525 | uint32_t cs = bu->count_stuff;
526 | bu->stuffed_bits = (bu->stuffed_bits & ((1 << cs) - 1)) | (data << cs);
527 | }
528 |
529 | // Pull bits from unstuffer (as specified in unstuf_set_count() )
530 | static int
531 | unstuf_pull_bits_rp2040(struct can2040_bitunstuffer *bu)
532 | {
533 | uint32_t sb = bu->stuffed_bits, edges = sb ^ (sb >> 1);
534 | uint32_t e2 = edges | (edges >> 1), e4 = e2 | (e2 >> 2), rm_bits = ~e4;
535 | uint32_t cs = bu->count_stuff, cu = bu->count_unstuff;
536 | if (!cs)
537 | // Need more data
538 | return 1;
539 | for (;;) {
540 | uint32_t try_cnt = cs > cu ? cu : cs;
541 | for (;;) {
542 | uint32_t try_mask = ((1 << try_cnt) - 1) << (cs + 1 - try_cnt);
543 | if (likely(!(rm_bits & try_mask))) {
544 | // No stuff bits in try_cnt bits - copy into unstuffed_bits
545 | bu->count_unstuff = cu = cu - try_cnt;
546 | bu->count_stuff = cs = cs - try_cnt;
547 | bu->unstuffed_bits |= ((sb >> cs) & ((1 << try_cnt) - 1)) << cu;
548 | if (! cu)
549 | // Extracted desired bits
550 | return 0;
551 | break;
552 | }
553 | bu->count_stuff = cs = cs - 1;
554 | if (rm_bits & (1 << (cs + 1))) {
555 | // High bit is a stuff bit
556 | if (unlikely(rm_bits & (1 << cs))) {
557 | // Six consecutive bits - a bitstuff error
558 | if (sb & (1 << cs))
559 | return -1;
560 | return -2;
561 | }
562 | break;
563 | }
564 | // High bit not a stuff bit - limit try_cnt and retry
565 | bu->count_unstuff = cu = cu - 1;
566 | bu->unstuffed_bits |= ((sb >> cs) & 1) << cu;
567 | try_cnt /= 2;
568 | }
569 | if (likely(!cs))
570 | // Need more data
571 | return 1;
572 | }
573 | }
574 |
575 | // Pull bits from unstuffer (optimized for rp2350)
576 | static int
577 | unstuf_pull_bits(struct can2040_bitunstuffer *bu)
578 | {
579 | if (!IS_RP2350)
580 | return unstuf_pull_bits_rp2040(bu);
581 | uint32_t sb = bu->stuffed_bits, edges = sb ^ (sb >> 1);
582 | uint32_t e2 = edges | (edges >> 1), e4 = e2 | (e2 >> 2), rm_bits = ~e4;
583 | uint32_t cs = bu->count_stuff, cu = bu->count_unstuff;
584 | for (;;) {
585 | if (!cs)
586 | // Need more data
587 | return 1;
588 | uint32_t try_cnt = cs > cu ? cu : cs;
589 | uint32_t try_mask = ((1 << try_cnt) - 1) << (cs + 1 - try_cnt);
590 | uint32_t rm_masked_bits = rm_bits & try_mask;
591 | if (likely(!rm_masked_bits)) {
592 | // No stuff bits in try_cnt bits - copy into unstuffed_bits
593 | bu->count_unstuff = cu = cu - try_cnt;
594 | bu->count_stuff = cs = cs - try_cnt;
595 | bu->unstuffed_bits |= ((sb >> cs) & ((1 << try_cnt) - 1)) << cu;
596 | if (! cu)
597 | // Extracted desired bits
598 | return 0;
599 | // Need more data
600 | return 1;
601 | }
602 | // Copy any leading bits prior to stuff bit (may be zero)
603 | uint32_t copy_cnt = cs - (31 - __builtin_clz(rm_masked_bits));
604 | cs -= copy_cnt;
605 | bu->count_unstuff = cu = cu - copy_cnt;
606 | bu->unstuffed_bits |= ((sb >> cs) & ((1 << copy_cnt) - 1)) << cu;
607 | // High bit is now a stuff bit - remove it
608 | bu->count_stuff = cs = cs - 1;
609 | if (unlikely(rm_bits & (1 << cs))) {
610 | // Six consecutive bits - a bitstuff error
611 | if (sb & (1 << cs))
612 | return -1;
613 | return -2;
614 | }
615 | }
616 | }
617 |
618 | // Return most recent raw (still stuffed) bits
619 | static uint32_t
620 | unstuf_get_raw(struct can2040_bitunstuffer *bu)
621 | {
622 | return bu->stuffed_bits >> bu->count_stuff;
623 | }
624 |
625 |
626 | /****************************************************************
627 | * Bit stuffing
628 | ****************************************************************/
629 |
630 | // Stuff 'num_bits' bits in '*pb' - upper bits must already be stuffed
631 | static uint32_t
632 | bitstuff_rp2040(uint32_t *pb, uint32_t num_bits)
633 | {
634 | uint32_t b = *pb, count = num_bits;
635 | for (;;) {
636 | uint32_t try_cnt = num_bits, edges = b ^ (b >> 1);
637 | uint32_t e2 = edges | (edges >> 1), e4 = e2 | (e2 >> 2), add_bits = ~e4;
638 | for (;;) {
639 | uint32_t try_mask = ((1 << try_cnt) - 1) << (num_bits - try_cnt);
640 | if (!(add_bits & try_mask)) {
641 | // No stuff bits needed in try_cnt bits
642 | if (try_cnt >= num_bits)
643 | goto done;
644 | num_bits -= try_cnt;
645 | try_cnt = (num_bits + 1) / 2;
646 | continue;
647 | }
648 | if (add_bits & (1 << (num_bits - 1))) {
649 | // A stuff bit must be inserted prior to the high bit
650 | uint32_t low_mask = (1 << num_bits) - 1, low = b & low_mask;
651 | uint32_t high = (b & ~(low_mask >> 1)) << 1;
652 | b = high ^ low ^ (1 << (num_bits - 1));
653 | count += 1;
654 | if (num_bits <= 4)
655 | goto done;
656 | num_bits -= 4;
657 | break;
658 | }
659 | // High bit doesn't need stuff bit - accept it, limit try_cnt, retry
660 | num_bits--;
661 | try_cnt /= 2;
662 | }
663 | }
664 | done:
665 | *pb = b;
666 | return count;
667 | }
668 |
669 | // Stuff 'num_bits' bits in '*pb' (optimized for rp2350)
670 | static uint32_t
671 | bitstuff(uint32_t *pb, uint32_t num_bits)
672 | {
673 | if (!IS_RP2350)
674 | return bitstuff_rp2040(pb, num_bits);
675 | uint32_t b = *pb, count = num_bits;
676 | for (;;) {
677 | uint32_t edges = b ^ (b >> 1);
678 | uint32_t e2 = edges | (edges >> 1), e4 = e2 | (e2 >> 2), add_bits = ~e4;
679 | uint32_t mask = (1 << num_bits) - 1, add_masked_bits = add_bits & mask;
680 | if (!add_masked_bits)
681 | // No more stuff bits needed
682 | break;
683 | // Insert a stuff bit
684 | uint32_t stuff_pos = 1 + 31 - __builtin_clz(add_masked_bits);
685 | uint32_t low_mask = (1 << stuff_pos) - 1, low = b & low_mask;
686 | uint32_t high = (b & ~(low_mask >> 1)) << 1;
687 | b = high ^ low ^ (1 << (stuff_pos - 1));
688 | count += 1;
689 | if (stuff_pos <= 4)
690 | break;
691 | num_bits = stuff_pos - 4;
692 | }
693 | *pb = b;
694 | return count;
695 | }
696 |
697 | // State storage for building bit stuffed transmit messages
698 | struct bitstuffer_s {
699 | uint32_t prev_stuffed, bitpos, *buf;
700 | };
701 |
702 | // Push 'count' bits of 'data' into stuffer without performing bit stuffing
703 | static void
704 | bs_pushraw(struct bitstuffer_s *bs, uint32_t data, uint32_t count)
705 | {
706 | uint32_t bitpos = bs->bitpos;
707 | uint32_t wp = bitpos / 32, bitused = bitpos % 32, bitavail = 32 - bitused;
708 | uint32_t *fb = &bs->buf[wp];
709 | if (bitavail >= count) {
710 | fb[0] |= data << (bitavail - count);
711 | } else {
712 | fb[0] |= data >> (count - bitavail);
713 | fb[1] |= data << (32 - (count - bitavail));
714 | }
715 | bs->bitpos = bitpos + count;
716 | }
717 |
718 | // Push 'count' bits of 'data' into stuffer
719 | static void
720 | bs_push(struct bitstuffer_s *bs, uint32_t data, uint32_t count)
721 | {
722 | data &= (1 << count) - 1;
723 | uint32_t stuf = (bs->prev_stuffed << count) | data;
724 | uint32_t newcount = bitstuff(&stuf, count);
725 | bs_pushraw(bs, stuf, newcount);
726 | bs->prev_stuffed = stuf;
727 | }
728 |
729 | // Pad final word of stuffer with high bits
730 | static uint32_t
731 | bs_finalize(struct bitstuffer_s *bs)
732 | {
733 | uint32_t bitpos = bs->bitpos;
734 | uint32_t words = DIV_ROUND_UP(bitpos, 32);
735 | uint32_t extra = words * 32 - bitpos;
736 | if (extra)
737 | bs->buf[words - 1] |= (1 << extra) - 1;
738 | return words;
739 | }
740 |
741 |
742 | /****************************************************************
743 | * Transmit state tracking
744 | ****************************************************************/
745 |
746 | // Transmit states (stored in cd->tx_state)
747 | enum {
748 | TS_IDLE = 0, TS_QUEUED = 1, TS_ACKING_RX = 2, TS_CONFIRM_TX = 3
749 | };
750 |
751 | // Calculate queue array position from a transmit index
752 | static uint32_t
753 | tx_qpos(struct can2040 *cd, uint32_t pos)
754 | {
755 | return pos % ARRAY_SIZE(cd->tx_queue);
756 | }
757 |
758 | // Queue the next message for transmission in the PIO
759 | static uint32_t
760 | tx_schedule_transmit(struct can2040 *cd)
761 | {
762 | if (cd->tx_state == TS_QUEUED && !pio_tx_did_fail(cd))
763 | // Already queued or actively transmitting
764 | return 0;
765 | uint32_t tx_pull_pos = cd->tx_pull_pos;
766 | if (readl(&cd->tx_push_pos) == tx_pull_pos) {
767 | // No new messages to transmit
768 | cd->tx_state = TS_IDLE;
769 | pio_signal_clear_txpending(cd);
770 | __DMB();
771 | if (likely(readl(&cd->tx_push_pos) == tx_pull_pos))
772 | return SI_TXPENDING;
773 | // Raced with can2040_transmit() - msg is now available for transmit
774 | pio_signal_set_txpending(cd);
775 | }
776 | cd->tx_state = TS_QUEUED;
777 | cd->stats.tx_attempt++;
778 | struct can2040_transmit *qt = &cd->tx_queue[tx_qpos(cd, tx_pull_pos)];
779 | pio_tx_send(cd, qt->stuffed_data, qt->stuffed_words);
780 | return 0;
781 | }
782 |
783 | // Setup PIO state for ack injection
784 | static void
785 | tx_inject_ack(struct can2040 *cd, uint32_t match_key)
786 | {
787 | cd->tx_state = TS_ACKING_RX;
788 | pio_tx_inject_ack(cd, match_key);
789 | }
790 |
791 | // Check if the current parsed message is feedback from current transmit
792 | static int
793 | tx_check_local_message(struct can2040 *cd)
794 | {
795 | if (cd->tx_state != TS_QUEUED)
796 | return 0;
797 | struct can2040_transmit *qt = &cd->tx_queue[tx_qpos(cd, cd->tx_pull_pos)];
798 | struct can2040_msg *pm = &cd->parse_msg, *tm = &qt->msg;
799 | if (tm->id == pm->id) {
800 | if (qt->crc != cd->parse_crc || tm->dlc != pm->dlc
801 | || tm->data32[0] != pm->data32[0] || tm->data32[1] != pm->data32[1])
802 | // Message with same id that differs in content - an error
803 | return -1;
804 | // This is a self transmit
805 | cd->tx_state = TS_CONFIRM_TX;
806 | return 1;
807 | }
808 | return 0;
809 | }
810 |
811 |
812 | /****************************************************************
813 | * Notification callbacks
814 | ****************************************************************/
815 |
816 | // Report state flags (stored in cd->report_state)
817 | enum {
818 | RS_NEED_EOF_FLAG = 1<<2,
819 | // States
820 | RS_IDLE = 0, RS_NEED_RX_ACK = 1, RS_NEED_TX_ACK = 2,
821 | RS_NEED_RX_EOF = RS_NEED_RX_ACK | RS_NEED_EOF_FLAG,
822 | RS_NEED_TX_EOF = RS_NEED_TX_ACK | RS_NEED_EOF_FLAG,
823 | };
824 |
825 | // Report error to calling code (via callback interface)
826 | static void
827 | report_callback_error(struct can2040 *cd, uint32_t error_code)
828 | {
829 | struct can2040_msg msg = {};
830 | cd->rx_cb(cd, CAN2040_NOTIFY_ERROR | error_code, &msg);
831 | }
832 |
833 | // Report a received message to calling code (via callback interface)
834 | static void
835 | report_callback_rx_msg(struct can2040 *cd)
836 | {
837 | cd->stats.rx_total++;
838 | cd->rx_cb(cd, CAN2040_NOTIFY_RX, &cd->parse_msg);
839 | }
840 |
841 | // Report a message that was successfully transmited (via callback interface)
842 | static void
843 | report_callback_tx_msg(struct can2040 *cd)
844 | {
845 | writel(&cd->tx_pull_pos, cd->tx_pull_pos + 1);
846 | cd->stats.tx_total++;
847 | cd->rx_cb(cd, CAN2040_NOTIFY_TX, &cd->parse_msg);
848 | }
849 |
850 | // EOF phase complete - report message (rx or tx) to calling code
851 | static void
852 | report_handle_eof(struct can2040 *cd)
853 | {
854 | if (cd->report_state & RS_NEED_EOF_FLAG) { // RS_NEED_xX_EOF
855 | // Successfully processed a new message - report to calling code
856 | pio_sync_normal_start_signal(cd);
857 | if (cd->report_state == RS_NEED_TX_EOF)
858 | report_callback_tx_msg(cd);
859 | else
860 | report_callback_rx_msg(cd);
861 | }
862 | cd->report_state = RS_IDLE;
863 | pio_match_clear(cd);
864 | }
865 |
866 | // Check if message being processed is an rx message (not self feedback from tx)
867 | static int
868 | report_is_not_in_tx(struct can2040 *cd)
869 | {
870 | return !(cd->report_state & RS_NEED_TX_ACK);
871 | }
872 |
873 | // Parser found a new message start
874 | static void
875 | report_note_message_start(struct can2040 *cd)
876 | {
877 | pio_irq_set(cd, SI_MAYTX);
878 | }
879 |
880 | // Setup for ack injection (if receiving) or ack confirmation (if transmit)
881 | static int
882 | report_note_crc_start(struct can2040 *cd)
883 | {
884 | int ret = tx_check_local_message(cd);
885 | if (ret) {
886 | if (ret < 0)
887 | return -1;
888 | // This is a self transmit - setup tx eof "matched" signal
889 | cd->report_state = RS_NEED_TX_ACK;
890 | uint32_t bits = (cd->parse_crc_bits << 9) | 0x0ff;
891 | pio_match_check(cd, pio_match_calc_key(bits, cd->parse_crc_pos + 9));
892 | return 0;
893 | }
894 |
895 | // Setup for ack inject (after rx fifos fully drained)
896 | cd->report_state = RS_NEED_RX_ACK;
897 | pio_signal_set_txpending(cd);
898 | pio_irq_set(cd, SI_MAYTX | SI_TXPENDING);
899 | return 0;
900 | }
901 |
902 | // Parser successfully found matching crc
903 | static void
904 | report_note_crc_success(struct can2040 *cd)
905 | {
906 | if (cd->report_state == RS_NEED_TX_ACK)
907 | // Enable "matched" irq for fast back-to-back transmit scheduling
908 | pio_irq_set(cd, SI_MAYTX | SI_MATCHED);
909 | }
910 |
911 | // Parser found successful ack
912 | static void
913 | report_note_ack_success(struct can2040 *cd)
914 | {
915 | if (cd->report_state == RS_IDLE)
916 | // Got "matched" signal already
917 | return;
918 | // Transition RS_NEED_xX_ACK to RS_NEED_xX_EOF
919 | cd->report_state |= RS_NEED_EOF_FLAG;
920 | }
921 |
922 | // Parser found successful EOF
923 | static void
924 | report_note_eof_success(struct can2040 *cd)
925 | {
926 | if (cd->report_state == RS_IDLE)
927 | // Got "matched" signal already
928 | return;
929 | report_handle_eof(cd);
930 | pio_irq_set(cd, SI_TXPENDING);
931 | }
932 |
933 | // Parser found unexpected data on input
934 | static void
935 | report_note_discarding(struct can2040 *cd)
936 | {
937 | if (cd->report_state != RS_IDLE) {
938 | cd->report_state = RS_IDLE;
939 | pio_match_clear(cd);
940 | }
941 | pio_sync_slow_start_signal(cd);
942 | pio_irq_set(cd, SI_MAYTX | SI_TXPENDING);
943 | }
944 |
945 | // Received PIO "ackdone" irq ("tx" state machine completed ack bit transmit)
946 | static void
947 | report_line_ackdone(struct can2040 *cd)
948 | {
949 | // Setup rx eof "matched" signal for fast rx callbacks
950 | uint32_t bits = (cd->parse_crc_bits << 8) | 0x7f;
951 | pio_match_check(cd, pio_match_calc_key(bits, cd->parse_crc_pos + 8));
952 | // Schedule next transmit (so it is ready for next frame line arbitration)
953 | uint32_t check_txpending = tx_schedule_transmit(cd);
954 | pio_irq_set(cd, SI_MAYTX | SI_MATCHED | check_txpending);
955 | }
956 |
957 | // Received PIO "matched" irq ("match" state machine detected eof match_key)
958 | static void
959 | report_line_matched(struct can2040 *cd)
960 | {
961 | // A match event indicates an ack and eof are present
962 | if (cd->report_state != RS_IDLE) {
963 | // Transition RS_NEED_xX_ACK to RS_NEED_xX_EOF (if not already there)
964 | cd->report_state |= RS_NEED_EOF_FLAG;
965 | report_handle_eof(cd);
966 | }
967 | // Implement fast back-to-back tx scheduling (if applicable)
968 | uint32_t check_txpending = tx_schedule_transmit(cd);
969 | pio_irq_set(cd, check_txpending);
970 | }
971 |
972 | // Received 10+ passive bits on the line (between 10 and 17 bits)
973 | static void
974 | report_line_maytx(struct can2040 *cd)
975 | {
976 | // Line is idle - may be unexpected EOF, missed ack injection,
977 | // or missed "matched" signal.
978 | if (cd->report_state != RS_IDLE)
979 | report_handle_eof(cd);
980 | uint32_t check_txpending = tx_schedule_transmit(cd);
981 | pio_irq_set(cd, check_txpending);
982 | }
983 |
984 | // Schedule a transmit
985 | static void
986 | report_line_txpending(struct can2040 *cd)
987 | {
988 | uint32_t pio_irqs = pio_irq_get(cd);
989 | if (pio_irqs == (SI_MAYTX | SI_TXPENDING | SI_RX_DATA)
990 | && cd->report_state == RS_NEED_RX_ACK) {
991 | // Ack inject request from report_note_crc_start()
992 | uint32_t mk = pio_match_calc_key(cd->parse_crc_bits, cd->parse_crc_pos);
993 | tx_inject_ack(cd, mk);
994 | pio_irq_set(cd, SI_MAYTX | SI_ACKDONE);
995 | return;
996 | }
997 | // Tx request from can2040_transmit(), report_note_eof_success(),
998 | // or report_note_discarding().
999 | uint32_t check_txpending = tx_schedule_transmit(cd);
1000 | pio_irq_set(cd, (pio_irqs & ~SI_TXPENDING) | check_txpending);
1001 | }
1002 |
1003 |
1004 | /****************************************************************
1005 | * Input state tracking
1006 | ****************************************************************/
1007 |
1008 | // Parsing states (stored in cd->parse_state)
1009 | enum {
1010 | MS_START, MS_HEADER, MS_EXT_HEADER, MS_DATA0, MS_DATA1,
1011 | MS_CRC, MS_ACK, MS_EOF0, MS_EOF1, MS_DISCARD
1012 | };
1013 |
1014 | // Reset any bits in the incoming parsing state
1015 | static void
1016 | data_state_clear_bits(struct can2040 *cd)
1017 | {
1018 | cd->raw_bit_count = cd->unstuf.stuffed_bits = cd->unstuf.count_stuff = 0;
1019 | }
1020 |
1021 | // Transition to the next parsing state
1022 | static void
1023 | data_state_go_next(struct can2040 *cd, uint32_t state, uint32_t num_bits)
1024 | {
1025 | cd->parse_state = state;
1026 | unstuf_set_count(&cd->unstuf, num_bits);
1027 | }
1028 |
1029 | // Transition to the MS_DISCARD state - drop all bits until 6 passive bits
1030 | static void
1031 | data_state_go_discard(struct can2040 *cd)
1032 | {
1033 | if (pio_rx_check_stall(cd)) {
1034 | // CPU couldn't keep up for some read data - must reset pio state
1035 | data_state_clear_bits(cd);
1036 | pio_sm_setup(cd);
1037 | report_callback_error(cd, 0);
1038 | }
1039 |
1040 | data_state_go_next(cd, MS_DISCARD, 32);
1041 |
1042 | // Clear report state and update hw irqs after transition to MS_DISCARD
1043 | report_note_discarding(cd);
1044 | }
1045 |
1046 | // Note a data parse error and transition to discard state
1047 | static void
1048 | data_state_go_error(struct can2040 *cd)
1049 | {
1050 | cd->stats.parse_error++;
1051 | data_state_go_discard(cd);
1052 | }
1053 |
1054 | // Received six dominant bits on the line
1055 | static void
1056 | data_state_line_error(struct can2040 *cd)
1057 | {
1058 | if (cd->parse_state == MS_DISCARD)
1059 | data_state_go_discard(cd);
1060 | else
1061 | data_state_go_error(cd);
1062 | }
1063 |
1064 | // Received six unexpected passive bits on the line
1065 | static void
1066 | data_state_line_passive(struct can2040 *cd)
1067 | {
1068 | if (cd->parse_state != MS_DISCARD && cd->parse_state != MS_START) {
1069 | // Bitstuff error
1070 | data_state_go_error(cd);
1071 | return;
1072 | }
1073 |
1074 | uint32_t stuffed_bits = unstuf_get_raw(&cd->unstuf);
1075 | uint32_t dom_bits = ~stuffed_bits;
1076 | if (!dom_bits) {
1077 | // Counter overflow in "sync" state machine - reset it
1078 | data_state_clear_bits(cd);
1079 | pio_sm_setup(cd);
1080 | data_state_go_discard(cd);
1081 | return;
1082 | }
1083 |
1084 | // Look for sof after 10 passive bits (most "PIO sync" will produce)
1085 | if (!(dom_bits & 0x3ff)) {
1086 | data_state_go_next(cd, MS_START, 1);
1087 | return;
1088 | }
1089 |
1090 | data_state_go_discard(cd);
1091 | }
1092 |
1093 | // Transition to MS_CRC state - await 16 bits of crc
1094 | static void
1095 | data_state_go_crc(struct can2040 *cd)
1096 | {
1097 | cd->parse_crc &= 0x7fff;
1098 |
1099 | // Calculate raw stuffed bits after crc and crc delimiter
1100 | uint32_t crcstart_bitpos = cd->raw_bit_count - cd->unstuf.count_stuff - 1;
1101 | uint32_t crc_bits = (unstuf_get_raw(&cd->unstuf) << 15) | cd->parse_crc;
1102 | uint32_t crc_bitcount = bitstuff(&crc_bits, 15 + 1) - 1;
1103 | cd->parse_crc_bits = (crc_bits << 1) | 0x01; // Add crc delimiter
1104 | cd->parse_crc_pos = crcstart_bitpos + crc_bitcount + 1;
1105 |
1106 | int ret = report_note_crc_start(cd);
1107 | if (ret) {
1108 | data_state_go_error(cd);
1109 | return;
1110 | }
1111 | data_state_go_next(cd, MS_CRC, 16);
1112 | }
1113 |
1114 | // Transition to MS_DATA0 state (if applicable) - await data bits
1115 | static void
1116 | data_state_go_data(struct can2040 *cd, uint32_t id, uint32_t data)
1117 | {
1118 | if (data & (0x03 << 4)) {
1119 | // Not a supported header
1120 | data_state_go_discard(cd);
1121 | return;
1122 | }
1123 | cd->parse_msg.data32[0] = cd->parse_msg.data32[1] = 0;
1124 | uint32_t dlc = data & 0x0f;
1125 | cd->parse_msg.dlc = dlc;
1126 | if (data & (1 << 6)) {
1127 | dlc = 0;
1128 | id |= CAN2040_ID_RTR;
1129 | }
1130 | cd->parse_msg.id = id;
1131 | if (dlc)
1132 | data_state_go_next(cd, MS_DATA0, dlc >= 4 ? 32 : dlc * 8);
1133 | else
1134 | data_state_go_crc(cd);
1135 | }
1136 |
1137 | // Handle reception of first bit of header (after start-of-frame (SOF))
1138 | static void
1139 | data_state_update_start(struct can2040 *cd, uint32_t data)
1140 | {
1141 | cd->parse_msg.id = data;
1142 | report_note_message_start(cd);
1143 | data_state_go_next(cd, MS_HEADER, 17);
1144 | }
1145 |
1146 | // Handle reception of next 17 header bits
1147 | static void
1148 | data_state_update_header(struct can2040 *cd, uint32_t data)
1149 | {
1150 | data |= cd->parse_msg.id << 17;
1151 | if ((data & 0x60) == 0x60) {
1152 | // Extended header
1153 | cd->parse_msg.id = data;
1154 | data_state_go_next(cd, MS_EXT_HEADER, 20);
1155 | return;
1156 | }
1157 | cd->parse_crc = crc_bytes(0, data, 3);
1158 | data_state_go_data(cd, (data >> 7) & 0x7ff, data);
1159 | }
1160 |
1161 | // Handle reception of additional 20 bits of "extended header"
1162 | static void
1163 | data_state_update_ext_header(struct can2040 *cd, uint32_t data)
1164 | {
1165 | uint32_t hdr1 = cd->parse_msg.id;
1166 | uint32_t crc = crc_bytes(0, hdr1 >> 4, 2);
1167 | cd->parse_crc = crc_bytes(crc, ((hdr1 & 0x0f) << 20) | data, 3);
1168 | uint32_t id = (((hdr1 << 11) & 0x1ffc0000) | ((hdr1 << 13) & 0x3e000)
1169 | | (data >> 7) | CAN2040_ID_EFF);
1170 | data_state_go_data(cd, id, data);
1171 | }
1172 |
1173 | // Handle reception of first 1-4 bytes of data content
1174 | static void
1175 | data_state_update_data0(struct can2040 *cd, uint32_t data)
1176 | {
1177 | uint32_t dlc = cd->parse_msg.dlc, bits = dlc >= 4 ? 32 : dlc * 8;
1178 | cd->parse_crc = crc_bytes(cd->parse_crc, data, dlc);
1179 | cd->parse_msg.data32[0] = __builtin_bswap32(data << (32 - bits));
1180 | if (dlc > 4)
1181 | data_state_go_next(cd, MS_DATA1, dlc >= 8 ? 32 : (dlc - 4) * 8);
1182 | else
1183 | data_state_go_crc(cd);
1184 | }
1185 |
1186 | // Handle reception of bytes 5-8 of data content
1187 | static void
1188 | data_state_update_data1(struct can2040 *cd, uint32_t data)
1189 | {
1190 | uint32_t dlc = cd->parse_msg.dlc, bits = dlc >= 8 ? 32 : (dlc - 4) * 8;
1191 | cd->parse_crc = crc_bytes(cd->parse_crc, data, dlc - 4);
1192 | cd->parse_msg.data32[1] = __builtin_bswap32(data << (32 - bits));
1193 | data_state_go_crc(cd);
1194 | }
1195 |
1196 | // Handle reception of 16 bits of message CRC (15 crc bits + crc delimiter)
1197 | static void
1198 | data_state_update_crc(struct can2040 *cd, uint32_t data)
1199 | {
1200 | if (((cd->parse_crc << 1) | 1) != data) {
1201 | data_state_go_error(cd);
1202 | return;
1203 | }
1204 |
1205 | report_note_crc_success(cd);
1206 | unstuf_clear_state(&cd->unstuf);
1207 | data_state_go_next(cd, MS_ACK, 2);
1208 | }
1209 |
1210 | // Handle reception of 2 bits of ack phase (ack, ack delimiter)
1211 | static void
1212 | data_state_update_ack(struct can2040 *cd, uint32_t data)
1213 | {
1214 | if (data != 0x01) {
1215 | // Undo unstuf_clear_state() for correct SOF detection in
1216 | // data_state_line_passive()
1217 | unstuf_restore_state(&cd->unstuf, (cd->parse_crc_bits << 2) | data);
1218 |
1219 | data_state_go_error(cd);
1220 | return;
1221 | }
1222 | report_note_ack_success(cd);
1223 | data_state_go_next(cd, MS_EOF0, 4);
1224 | }
1225 |
1226 | // Handle reception of first four end-of-frame (EOF) bits
1227 | static void
1228 | data_state_update_eof0(struct can2040 *cd, uint32_t data)
1229 | {
1230 | if (data != 0x0f || pio_rx_check_stall(cd)) {
1231 | data_state_go_error(cd);
1232 | return;
1233 | }
1234 | unstuf_clear_state(&cd->unstuf);
1235 | data_state_go_next(cd, MS_EOF1, 5);
1236 | }
1237 |
1238 | // Handle reception of end-of-frame (EOF) bits 5-7 and first two IFS bits
1239 | static void
1240 | data_state_update_eof1(struct can2040 *cd, uint32_t data)
1241 | {
1242 | if (data == 0x1f) {
1243 | // Success
1244 | report_note_eof_success(cd);
1245 | data_state_go_next(cd, MS_START, 1);
1246 | } else if (data >= 0x1c || (data >= 0x18 && report_is_not_in_tx(cd))) {
1247 | // Message fully transmitted - followed by "overload frame"
1248 | report_note_eof_success(cd);
1249 | data_state_go_discard(cd);
1250 | } else {
1251 | data_state_go_error(cd);
1252 | }
1253 | }
1254 |
1255 | // Handle data received while in MS_DISCARD state
1256 | static void
1257 | data_state_update_discard(struct can2040 *cd, uint32_t data)
1258 | {
1259 | data_state_go_discard(cd);
1260 | }
1261 |
1262 | // Update parsing state after reading the bits of the current field
1263 | static void
1264 | data_state_update(struct can2040 *cd, uint32_t data)
1265 | {
1266 | switch (cd->parse_state) {
1267 | case MS_START: data_state_update_start(cd, data); break;
1268 | case MS_HEADER: data_state_update_header(cd, data); break;
1269 | case MS_EXT_HEADER: data_state_update_ext_header(cd, data); break;
1270 | case MS_DATA0: data_state_update_data0(cd, data); break;
1271 | case MS_DATA1: data_state_update_data1(cd, data); break;
1272 | case MS_CRC: data_state_update_crc(cd, data); break;
1273 | case MS_ACK: data_state_update_ack(cd, data); break;
1274 | case MS_EOF0: data_state_update_eof0(cd, data); break;
1275 | case MS_EOF1: data_state_update_eof1(cd, data); break;
1276 | case MS_DISCARD: data_state_update_discard(cd, data); break;
1277 | }
1278 | }
1279 |
1280 |
1281 | /****************************************************************
1282 | * Input processing
1283 | ****************************************************************/
1284 |
1285 | // Process incoming data from PIO "rx" state machine
1286 | static void
1287 | process_rx(struct can2040 *cd, uint32_t rx_data)
1288 | {
1289 | unstuf_add_bits(&cd->unstuf, rx_data, PIO_RX_WAKE_BITS);
1290 | cd->raw_bit_count += PIO_RX_WAKE_BITS;
1291 |
1292 | // undo bit stuffing
1293 | for (;;) {
1294 | int ret = unstuf_pull_bits(&cd->unstuf);
1295 | if (likely(ret > 0)) {
1296 | // Need more data
1297 | break;
1298 | } else if (likely(!ret)) {
1299 | // Pulled the next field - process it
1300 | data_state_update(cd, cd->unstuf.unstuffed_bits);
1301 | } else {
1302 | if (ret == -1)
1303 | // 6 consecutive high bits
1304 | data_state_line_passive(cd);
1305 | else
1306 | // 6 consecutive low bits
1307 | data_state_line_error(cd);
1308 | }
1309 | }
1310 | }
1311 |
1312 | // Main API irq notification function
1313 | void
1314 | can2040_pio_irq_handler(struct can2040 *cd)
1315 | {
1316 | pio_hw_t *pio_hw = cd->pio_hw;
1317 | uint32_t ints = pio_hw->ints0;
1318 | while (likely(ints & SI_RX_DATA)) {
1319 | uint32_t rx_data = pio_hw->rxf[SM_RX];
1320 | process_rx(cd, rx_data);
1321 | ints = pio_hw->ints0;
1322 | if (likely(!ints))
1323 | return;
1324 | }
1325 |
1326 | if (ints & SI_ACKDONE)
1327 | // Ack of received message completed successfully
1328 | report_line_ackdone(cd);
1329 | else if (ints & SI_MATCHED)
1330 | // Transmit message completed successfully
1331 | report_line_matched(cd);
1332 | else if (ints & SI_MAYTX)
1333 | // Bus is idle, but not all bits may have been flushed yet
1334 | report_line_maytx(cd);
1335 | else if (ints & SI_TXPENDING)
1336 | // Schedule a transmit
1337 | report_line_txpending(cd);
1338 | }
1339 |
1340 |
1341 | /****************************************************************
1342 | * Transmit queuing
1343 | ****************************************************************/
1344 |
1345 | // API function to check if transmit space available
1346 | int
1347 | can2040_check_transmit(struct can2040 *cd)
1348 | {
1349 | uint32_t tx_pull_pos = readl(&cd->tx_pull_pos);
1350 | uint32_t tx_push_pos = cd->tx_push_pos;
1351 | uint32_t pending = tx_push_pos - tx_pull_pos;
1352 | return pending < ARRAY_SIZE(cd->tx_queue);
1353 | }
1354 |
1355 | // API function to transmit a message
1356 | int
1357 | can2040_transmit(struct can2040 *cd, struct can2040_msg *msg)
1358 | {
1359 | uint32_t tx_pull_pos = readl(&cd->tx_pull_pos);
1360 | uint32_t tx_push_pos = cd->tx_push_pos;
1361 | uint32_t pending = tx_push_pos - tx_pull_pos;
1362 | if (pending >= ARRAY_SIZE(cd->tx_queue))
1363 | // Tx queue full
1364 | return -1;
1365 |
1366 | // Copy msg into transmit queue
1367 | struct can2040_transmit *qt = &cd->tx_queue[tx_qpos(cd, tx_push_pos)];
1368 | uint32_t id = msg->id;
1369 | if (id & CAN2040_ID_EFF)
1370 | qt->msg.id = id & ~0x20000000;
1371 | else
1372 | qt->msg.id = id & (CAN2040_ID_RTR | 0x7ff);
1373 | qt->msg.dlc = msg->dlc & 0x0f;
1374 | uint32_t data_len = qt->msg.dlc > 8 ? 8 : qt->msg.dlc;
1375 | if (qt->msg.id & CAN2040_ID_RTR)
1376 | data_len = 0;
1377 | qt->msg.data32[0] = qt->msg.data32[1] = 0;
1378 | memcpy(qt->msg.data, msg->data, data_len);
1379 |
1380 | // Calculate crc and stuff bits
1381 | uint32_t crc = 0;
1382 | memset(qt->stuffed_data, 0, sizeof(qt->stuffed_data));
1383 | struct bitstuffer_s bs = { 1, 0, qt->stuffed_data };
1384 | uint32_t edlc = qt->msg.dlc | (qt->msg.id & CAN2040_ID_RTR ? 0x40 : 0);
1385 | if (qt->msg.id & CAN2040_ID_EFF) {
1386 | // Extended header
1387 | uint32_t id = qt->msg.id;
1388 | uint32_t h1 = ((id & 0x1ffc0000) >> 11) | 0x60 | ((id & 0x3e000) >> 13);
1389 | uint32_t h2 = ((id & 0x1fff) << 7) | edlc;
1390 | crc = crc_bytes(crc, h1 >> 4, 2);
1391 | crc = crc_bytes(crc, ((h1 & 0x0f) << 20) | h2, 3);
1392 | bs_push(&bs, h1, 19);
1393 | bs_push(&bs, h2, 20);
1394 | } else {
1395 | // Standard header
1396 | uint32_t hdr = ((qt->msg.id & 0x7ff) << 7) | edlc;
1397 | crc = crc_bytes(crc, hdr, 3);
1398 | bs_push(&bs, hdr, 19);
1399 | }
1400 | uint32_t i;
1401 | for (i=0; imsg.data[i];
1403 | crc = crc_byte(crc, v);
1404 | bs_push(&bs, v, 8);
1405 | }
1406 | qt->crc = crc & 0x7fff;
1407 | bs_push(&bs, qt->crc, 15);
1408 | bs_pushraw(&bs, 1, 1);
1409 | qt->stuffed_words = bs_finalize(&bs);
1410 |
1411 | // Submit
1412 | writel(&cd->tx_push_pos, tx_push_pos + 1);
1413 |
1414 | // Wakeup if in TS_IDLE state
1415 | __DMB();
1416 | pio_signal_set_txpending(cd);
1417 |
1418 | return 0;
1419 | }
1420 |
1421 |
1422 | /****************************************************************
1423 | * Setup
1424 | ****************************************************************/
1425 |
1426 | // API function to initialize can2040 code
1427 | void
1428 | can2040_setup(struct can2040 *cd, uint32_t pio_num)
1429 | {
1430 | memset(cd, 0, sizeof(*cd));
1431 | cd->pio_num = !!pio_num;
1432 | cd->pio_hw = cd->pio_num ? pio1_hw : pio0_hw;
1433 | #if IS_RP2350
1434 | if (pio_num == 2) {
1435 | cd->pio_num = pio_num;
1436 | cd->pio_hw = pio2_hw;
1437 | }
1438 | #endif
1439 | }
1440 |
1441 | // API function to configure callback
1442 | void
1443 | can2040_callback_config(struct can2040 *cd, can2040_rx_cb rx_cb)
1444 | {
1445 | cd->rx_cb = rx_cb;
1446 | }
1447 |
1448 | // API function to start CANbus interface
1449 | void
1450 | can2040_start(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate
1451 | , uint32_t gpio_rx, uint32_t gpio_tx)
1452 | {
1453 | cd->gpio_rx = gpio_rx;
1454 | cd->gpio_tx = gpio_tx;
1455 | data_state_clear_bits(cd);
1456 | pio_setup(cd, sys_clock, bitrate);
1457 | data_state_go_discard(cd);
1458 | }
1459 |
1460 | // API function to stop can2040 code
1461 | void
1462 | can2040_stop(struct can2040 *cd)
1463 | {
1464 | pio_irq_disable(cd);
1465 | pio_sm_setup(cd);
1466 | }
1467 |
1468 | // API function to access can2040 statistics
1469 | void
1470 | can2040_get_statistics(struct can2040 *cd, struct can2040_stats *stats)
1471 | {
1472 | for (;;) {
1473 | memcpy(stats, &cd->stats, sizeof(*stats));
1474 | if (memcmp(stats, &cd->stats, sizeof(*stats)) == 0)
1475 | // Successfully copied data
1476 | return;
1477 | // Raced with irq handler update - retry copy
1478 | }
1479 | }
1480 |
--------------------------------------------------------------------------------
/src/can2040.h:
--------------------------------------------------------------------------------
1 | #ifndef _CAN2040_H
2 | #define _CAN2040_H
3 |
4 | #include // uint32_t
5 |
6 | struct can2040_msg {
7 | uint32_t id;
8 | uint32_t dlc;
9 | union {
10 | uint8_t data[8];
11 | uint32_t data32[2];
12 | };
13 | };
14 |
15 | enum {
16 | CAN2040_ID_RTR = 1<<30,
17 | CAN2040_ID_EFF = 1<<31,
18 | };
19 |
20 | enum {
21 | CAN2040_NOTIFY_RX = 1<<20,
22 | CAN2040_NOTIFY_TX = 1<<21,
23 | CAN2040_NOTIFY_ERROR = 1<<23,
24 | };
25 | struct can2040;
26 | typedef void (*can2040_rx_cb)(struct can2040 *cd, uint32_t notify
27 | , struct can2040_msg *msg);
28 |
29 | struct can2040_stats {
30 | uint32_t rx_total, tx_total;
31 | uint32_t tx_attempt;
32 | uint32_t parse_error;
33 | };
34 |
35 | void can2040_setup(struct can2040 *cd, uint32_t pio_num);
36 | void can2040_callback_config(struct can2040 *cd, can2040_rx_cb rx_cb);
37 | void can2040_start(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate
38 | , uint32_t gpio_rx, uint32_t gpio_tx);
39 | void can2040_stop(struct can2040 *cd);
40 | void can2040_get_statistics(struct can2040 *cd, struct can2040_stats *stats);
41 | void can2040_pio_irq_handler(struct can2040 *cd);
42 | int can2040_check_transmit(struct can2040 *cd);
43 | int can2040_transmit(struct can2040 *cd, struct can2040_msg *msg);
44 |
45 |
46 | /****************************************************************
47 | * Internal definitions
48 | ****************************************************************/
49 |
50 | struct can2040_bitunstuffer {
51 | uint32_t stuffed_bits, count_stuff;
52 | uint32_t unstuffed_bits, count_unstuff;
53 | };
54 |
55 | struct can2040_transmit {
56 | struct can2040_msg msg;
57 | uint32_t crc, stuffed_words, stuffed_data[5];
58 | };
59 |
60 | struct can2040 {
61 | // Setup
62 | uint32_t pio_num;
63 | void *pio_hw;
64 | uint32_t gpio_rx, gpio_tx;
65 | can2040_rx_cb rx_cb;
66 | struct can2040_stats stats;
67 |
68 | // Bit unstuffing
69 | struct can2040_bitunstuffer unstuf;
70 | uint32_t raw_bit_count;
71 |
72 | // Input data state
73 | uint32_t parse_state;
74 | uint32_t parse_crc, parse_crc_bits, parse_crc_pos;
75 | struct can2040_msg parse_msg;
76 |
77 | // Reporting
78 | uint32_t report_state;
79 |
80 | // Transmits
81 | uint32_t tx_state;
82 | uint32_t tx_pull_pos, tx_push_pos;
83 | struct can2040_transmit tx_queue[4];
84 | };
85 |
86 | #endif // can2040.h
87 |
--------------------------------------------------------------------------------