tag:blogger.com,1999:blog-5858200123900482672024-03-12T22:15:09.018-07:00All things embeddedtcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.comBlogger65125tag:blogger.com,1999:blog-585820012390048267.post-18581501316564387902023-08-29T09:53:00.000-07:002023-08-29T09:53:43.172-07:00Sipeed M1S Dock Hello world how to<p> Sipeed is selling a M1s Dock at several places pricing is around $13USD. The main processor, has uses the BL808 which has 3 processors: </p><ol style="text-align: left;"><li>RISC-V 64 bit RV64IMAFCV (D0)</li><ul><li>Uses serial pins <br /> </li></ul><li>RISC-V 32 bit RV32IMAFCP (M0)</li><ul><li>/dev/ttyUSB1<br /></li></ul><li>RISC-V 32 bit RV32EMC (LP)</li><ul><li>(Have not tested)<br /></li></ul></ol>tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-6677303181564834462022-08-26T15:25:00.003-07:002022-08-31T06:03:22.828-07:00SPI slave as a Wishbone master for offloading Pi Zero Flight controller (BaseFlight)<p>(This is still work in progress but wanted to publish it and keep working on it)</p><p> The Raspberry PI zero has a good price performance ratio, the 2W even better. I have been working on porting <a href="https://github.com/tcmichals/betaflight">BaseFlight</a> (Flight controller software for STM32 micro-controller) to Linux running on the PI. The code is working with a MPU9250. </p><p>The hardware will be a PI Zero or a PI Zero 2W (Still need one), SPI0.0 to the IMU, the SPI0.1 connected to the FPGA. The FPGA will create the signals needed for OneShot, decode 6 channels of PWM (I have an old Transmitter that supports 6 channels of PWM), and LED controller. </p><p>Will be using the <a href="https://digilent.com/shop/cmod-s7-breadboardable-spartan-7-fpga-module/">CS7Mod</a>, its small, has 4 LEDs and 1 RGB. LEDS will be used for status indication for BaseFlight.</p><p>So, what will be the communication protocol over SPI? Simple Wishbone bus instructions, Read/Write using address and data. </p><p>The<a href="https://github.com/alexforencich/verilog-wishbone"> WishBone master</a> is interface to the SPI Slave, so the PI Zero will be the master. Here is commands for a read and write</p><p></p><ul style="text-align: left;"><li>Command string</li><ul><li>1 byte command, either Read/Write</li><li>4 byte address Highest address first (Big Endian)</li><li>2 byte length: first byte is the highest followed by the lowest</li><li>4 bytes of data, first byte is the lowest byte. (Little endian)</li></ul><li>Read: example using command line: <ul><li>printf '\xA1\x1\x2\x3\x0\x0\x4\xf\x00\x00\x0\x0' | spi-pipe -m 0 -s 1000000 -d /dev/spidev0.1 | hexdump -C</li></ul></li><li>Wite: </li><ul><li>printf '\xA2\x1\x2\x3\x0\x0\x4\xf\xff\xff\x11\0' | spi-pipe -m 0 -s 1000000 -d /dev/spidev0.1 | hexdump -C</li></ul></ul><div>The reason for using a Wishbone bus:</div><div><ol style="text-align: left;"><li>Simple</li><li>Use existing code for<a href="https://github.com/alexforencich/verilog-wishbone"> Wishbone Master</a> </li><li>Easy to test</li><li>Extendable (More on that later)</li></ol><div><br /></div></div><div>Right now, there are 3 wishbone peripherals</div><div><ol style="text-align: left;"><li>LED controller</li><ol><li>address 0: set 32 bit register</li><li>address 4: xor 32 bit register (blink)</li><li>address 8: clear 32 bit register</li></ol><li>PWM decoder </li><ol><li>6 32 bit registers. </li></ol><li>One Shot generator</li><ol><li>4 32 bit registers</li></ol></ol><div>Here is screen shot of vivado, this is only for LED controller:</div></div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgPpwR9gDMHQe122ZfLBtfC4UVO-VmwiqL7t5sIRcOhYjfpbEitNFiru64U4W21zYoQYVqCO33jR7OL8rL9JBVSMF-lDnBmdnJezW6Ev8FhI4IMBwPul6rzEpAWE9l8Ps0p7zVdXtTgtge-sQt9BU2YyWTwvUFUve_HI_hgzOl0f9njxsGSFeu99WiPWQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1200" data-original-width="1920" height="358" src="https://blogger.googleusercontent.com/img/a/AVvXsEgPpwR9gDMHQe122ZfLBtfC4UVO-VmwiqL7t5sIRcOhYjfpbEitNFiru64U4W21zYoQYVqCO33jR7OL8rL9JBVSMF-lDnBmdnJezW6Ev8FhI4IMBwPul6rzEpAWE9l8Ps0p7zVdXtTgtge-sQt9BU2YyWTwvUFUve_HI_hgzOl0f9njxsGSFeu99WiPWQ=w586-h358" width="586" /></a></div><br /><br /></div><div><br /></div><p></p><p><br /></p><p><br /></p><p><br /></p><p><br /></p>tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-7629160300181379602020-10-20T19:33:00.002-07:002020-10-20T19:35:22.220-07:00Using asyncio with libgpiod on an OrangePI Zero<p> Python is a great tool to create simple/fast test code, combine that with libgpiod, now you can toggle and monitor gpio pins. </p><p>In recent Linux kernels libgpiod is a library to write C/C++ and Python to toggle and monitor general purpose pins. There are plenty examples for <a href="https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/bindings/python/examples">python</a>. I use buildroot to create a Linux distro, one option under hardware is to install libgpiod and if you have python3 selected now you can write python scripts. <br /></p><p>Here is two basic classes gpiowrapper.py:</p><div style="background-color: #1e1e1e; color: #d4d4d4; font-family: "Droid Sans Mono", "monospace", monospace, "Droid Sans Fallback"; font-size: 14px; font-weight: normal; line-height: 19px; white-space: pre;"><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> gpiod</span></div><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> threading</span></div><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> asyncio</span></div><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> logging</span></div><br /><div><span style="color: #569cd6;">class</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">OutputPin</span><span style="color: #d4d4d4;">:</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">def</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">__init__</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">self</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">chip</span><span style="color: #d4d4d4;"> =</span><span style="color: #ce9178;">"gpiochip0"</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">pin</span><span style="color: #d4d4d4;"> = </span><span style="color: #b5cea8;">0</span><span style="color: #d4d4d4;">):</span></div><br /><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">"args chip=</span><span style="color: #569cd6;">{0}</span><span style="color: #ce9178;"> pin=</span><span style="color: #569cd6;">{1}</span><span style="color: #ce9178;">"</span><span style="color: #d4d4d4;">.format(chip, pin))</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.chip = gpiod.Chip(chip)</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">if</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.chip </span><span style="color: #569cd6;">is</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">None</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> logging.error(</span><span style="color: #ce9178;">"chip not found"</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">else</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">"type </span><span style="color: #569cd6;">{0}</span><span style="color: #ce9178;"> </span><span style="color: #569cd6;">{1}</span><span style="color: #ce9178;">"</span><span style="color: #d4d4d4;">.format(</span><span style="color: #4ec9b0;">type</span><span style="color: #d4d4d4;">(</span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.chip), </span><span style="color: #4ec9b0;">type</span><span style="color: #d4d4d4;">(pin)))</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.line = </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.chip.get_line(pin)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.line.request(</span><span style="color: #9cdcfe;">consumer</span><span style="color: #d4d4d4;">=chip, </span><span style="color: #9cdcfe;">type</span><span style="color: #d4d4d4;">=gpiod.LINE_REQ_DIR_OUT)</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">def</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">set_level</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">self</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">level</span><span style="color: #d4d4d4;">=</span><span style="color: #b5cea8;">0</span><span style="color: #d4d4d4;">):</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">if</span><span style="color: #d4d4d4;"> level:</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.line.set_value(</span><span style="color: #b5cea8;">1</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">else</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.line.set_value(</span><span style="color: #b5cea8;">0</span><span style="color: #d4d4d4;">)</span></div><br /><div><span style="color: #569cd6;">class</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">EventPin</span><span style="color: #d4d4d4;">:</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">def</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">__init__</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">self</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">chip</span><span style="color: #d4d4d4;"> = </span><span style="color: #ce9178;">"gpiochip0"</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">pin</span><span style="color: #d4d4d4;">=</span><span style="color: #b5cea8;">0</span><span style="color: #d4d4d4;"> ):</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">try</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">._pin = pin</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.chip = gpiod.Chip(chip)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">if</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.chip </span><span style="color: #569cd6;">is</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">None</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> logging.error(</span><span style="color: #ce9178;">"chip not found"</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">else</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">"type </span><span style="color: #569cd6;">{0}</span><span style="color: #ce9178;"> </span><span style="color: #569cd6;">{1}</span><span style="color: #ce9178;">"</span><span style="color: #d4d4d4;">.format(</span><span style="color: #4ec9b0;">type</span><span style="color: #d4d4d4;">(</span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.chip), </span><span style="color: #4ec9b0;">type</span><span style="color: #d4d4d4;">(pin)))</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.line = </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.chip.get_line(pin)</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.line.request(</span><span style="color: #9cdcfe;">consumer</span><span style="color: #d4d4d4;">=chip, </span><span style="color: #9cdcfe;">type</span><span style="color: #d4d4d4;">=gpiod.LINE_REQ_EV_RISING_EDGE)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.on_wait = asyncio.Queue()</span></div><br /><div><span style="color: #d4d4d4;"> asyncio.get_running_loop().add_reader( </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.line.event_get_fd(), </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.event_cb)</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">except</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Exception</span><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">as</span><span style="color: #d4d4d4;"> ex:</span></div><div><span style="color: #d4d4d4;"> logging.error(</span><span style="color: #ce9178;">"Error: </span><span style="color: #569cd6;">{0}</span><span style="color: #ce9178;">"</span><span style="color: #d4d4d4;">.format(</span><span style="color: #4ec9b0;">str</span><span style="color: #d4d4d4;">(ex)))</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">def</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">event_cb</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">self</span><span style="color: #d4d4d4;">):</span></div><div><span style="color: #d4d4d4;"> event = </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.line.event_read()</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">if</span><span style="color: #d4d4d4;"> event.type == gpiod.LineEvent.RISING_EDGE:</span></div><div><span style="color: #d4d4d4;"> evstr = </span><span style="color: #ce9178;">' RISING EDGE'</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">elif</span><span style="color: #d4d4d4;"> event.type == gpiod.LineEvent.FALLING_EDGE:</span></div><div><span style="color: #d4d4d4;"> evstr = </span><span style="color: #ce9178;">'FALLING EDGE'</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">else</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">raise</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">TypeError</span><span style="color: #d4d4d4;">(</span><span style="color: #ce9178;">'Invalid event type'</span><span style="color: #d4d4d4;">)</span></div><br /><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">" event </span><span style="color: #569cd6;">{0}</span><span style="color: #ce9178;">"</span><span style="color: #d4d4d4;">.format(evstr))</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.on_wait.put_nowait(event.type)</span></div><div><span style="color: #d4d4d4;"> </span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">async</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">def</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">wait</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">self</span><span style="color: #d4d4d4;">):</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">await</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">self</span><span style="color: #d4d4d4;">.on_wait.get()</span></div><br /><br /><br /><br /></div><p> </p><p>The EventPin class can be used with asyncio to wait for Edge Triggered GPIO. The key line is adding file descriptor of the event pin to asyncio and perform a callback when the FD is changes and push the event into a queue so await can be used. <br /></p><p>Here is a simple blink.py:</p><div style="background-color: #1e1e1e; color: #d4d4d4; font-family: "Droid Sans Mono", "monospace", monospace, "Droid Sans Fallback"; font-size: 14px; font-weight: normal; line-height: 19px; white-space: pre;"><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> gpiod</span></div><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> sys</span></div><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> time</span></div><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> argparse</span></div><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> gpiowrapper</span></div><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> asyncio</span></div><div><span style="color: #c586c0;">import</span><span style="color: #d4d4d4;"> logging</span></div><br /><div><span style="color: #569cd6;">async</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">def</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">blink</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">io_chip</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">o_pin</span><span style="color: #d4d4d4;">):</span></div><br /><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">"blink"</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> pin = gpiowrapper.OutputPin(</span><span style="color: #9cdcfe;">chip</span><span style="color: #d4d4d4;">=io_chip, </span><span style="color: #9cdcfe;">pin</span><span style="color: #d4d4d4;">=</span><span style="color: #4ec9b0;">int</span><span style="color: #d4d4d4;">(o_pin))</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">while</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">True</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> pin.set_level(</span><span style="color: #b5cea8;">0</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">await</span><span style="color: #d4d4d4;"> asyncio.sleep(</span><span style="color: #b5cea8;">0.1</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> pin.set_level(</span><span style="color: #b5cea8;">1</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">await</span><span style="color: #d4d4d4;"> asyncio.sleep(</span><span style="color: #b5cea8;">0.1</span><span style="color: #d4d4d4;">)</span></div><br /><br /><div><span style="color: #569cd6;">async</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">def</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">toggleTask</span><span style="color: #d4d4d4;">( </span><span style="color: #9cdcfe;">o_pin</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">timeout</span><span style="color: #d4d4d4;">):</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">try</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">while</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">True</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> o_pin.set_level(</span><span style="color: #b5cea8;">0</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">await</span><span style="color: #d4d4d4;"> asyncio.sleep(timeout)</span></div><div><span style="color: #d4d4d4;"> o_pin.set_level(</span><span style="color: #b5cea8;">1</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">await</span><span style="color: #d4d4d4;"> asyncio.sleep(timeout)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">except</span><span style="color: #d4d4d4;"> </span><span style="color: #4ec9b0;">Exception</span><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">as</span><span style="color: #d4d4d4;"> ex:</span></div><div><span style="color: #d4d4d4;"> logging.error(</span><span style="color: #ce9178;">"error </span><span style="color: #569cd6;">{0}</span><span style="color: #ce9178;">"</span><span style="color: #d4d4d4;">.format(</span><span style="color: #4ec9b0;">str</span><span style="color: #d4d4d4;">(ex)))</span></div><br /><div><span style="color: #569cd6;">async</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">def</span><span style="color: #d4d4d4;"> </span><span style="color: #dcdcaa;">monitor_event</span><span style="color: #d4d4d4;">(</span><span style="color: #9cdcfe;">io_chip</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">output_pin</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">event_pin</span><span style="color: #d4d4d4;">):</span></div><br /><div><span style="color: #d4d4d4;"> o_pin = gpiowrapper.OutputPin(io_chip, output_pin)</span></div><div><span style="color: #d4d4d4;"> evt_pin = gpiowrapper.EventPin(io_chip, event_pin)</span></div><br /><div><span style="color: #d4d4d4;"> toggle_task = asyncio.create_task(toggleTask(o_pin, </span><span style="color: #b5cea8;">.5</span><span style="color: #d4d4d4;">))</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">while</span><span style="color: #d4d4d4;"> </span><span style="color: #569cd6;">True</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> val = </span><span style="color: #c586c0;">await</span><span style="color: #d4d4d4;"> evt_pin.wait()</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">if</span><span style="color: #d4d4d4;"> val == gpiod.LineEvent.RISING_EDGE:</span></div><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">"Rising edge event"</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">elif</span><span style="color: #d4d4d4;"> val == gpiod.LineEvent.FALLING_EDGE:</span></div><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">"Falling edge event"</span><span style="color: #d4d4d4;">)</span></div><br /><div><span style="color: #c586c0;">if</span><span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">__name__</span><span style="color: #d4d4d4;"> == </span><span style="color: #ce9178;">"__main__"</span><span style="color: #d4d4d4;">:</span></div><div><span style="color: #d4d4d4;"> logging.basicConfig(</span><span style="color: #9cdcfe;">format</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">'</span><span style="color: #569cd6;">%(asctime)s</span><span style="color: #ce9178;"> </span><span style="color: #569cd6;">%(levelname)s</span><span style="color: #ce9178;"> </span><span style="color: #569cd6;">%(filename)s</span><span style="color: #ce9178;">:</span><span style="color: #569cd6;">%(lineno)s</span><span style="color: #ce9178;"> - </span><span style="color: #569cd6;">%(funcName)20s</span><span style="color: #ce9178;">() </span><span style="color: #569cd6;">%(message)s</span><span style="color: #ce9178;">'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">level</span><span style="color: #d4d4d4;">=logging.DEBUG)</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #6a9955;"># execute only if run as a script</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #6a9955;"># Create the parser</span></div><div><span style="color: #d4d4d4;"> my_parser = argparse.ArgumentParser(</span><span style="color: #9cdcfe;">description</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">'List the content of a folder'</span><span style="color: #d4d4d4;">)</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #6a9955;"># Add the arguments</span></div><div><span style="color: #d4d4d4;"> my_parser.add_argument(</span><span style="color: #ce9178;">'-chip'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">help</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">'chip '</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> my_parser.add_argument(</span><span style="color: #ce9178;">'-opin'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">type</span><span style="color: #d4d4d4;">=</span><span style="color: #4ec9b0;">int</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">help</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">'output pin'</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> my_parser.add_argument(</span><span style="color: #ce9178;">'--epin'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">type</span><span style="color: #d4d4d4;">=</span><span style="color: #4ec9b0;">int</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">help</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">'event pin'</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> my_parser.add_argument(</span><span style="color: #ce9178;">'--blink'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">help</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">'event pin'</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> my_parser.add_argument(</span><span style="color: #ce9178;">'--event'</span><span style="color: #d4d4d4;">, </span><span style="color: #9cdcfe;">help</span><span style="color: #d4d4d4;">=</span><span style="color: #ce9178;">'event pin'</span><span style="color: #d4d4d4;">)</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #6a9955;"># Execute the parse_args() method</span></div><div><span style="color: #d4d4d4;"> args = my_parser.parse_args()</span></div><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">"main"</span><span style="color: #d4d4d4;">)</span></div><br /><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">if</span><span style="color: #d4d4d4;"> args.blink:</span></div><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">"run blink"</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> asyncio.run(blink( args.chip, args.opin))</span></div><div><span style="color: #d4d4d4;"> </span><span style="color: #c586c0;">if</span><span style="color: #d4d4d4;"> args.event:</span></div><div><span style="color: #d4d4d4;"> logging.debug(</span><span style="color: #ce9178;">"monitor"</span><span style="color: #d4d4d4;">)</span></div><div><span style="color: #d4d4d4;"> asyncio.run(monitor_event(args.chip, args.opin, args.epin))</span></div><br /><div><span style="color: #d4d4d4;"> </span></div></div><p> </p><p>Load both files onto the Orange PI Zero. </p><p>python blink.py -chip gpiochip0 -opin 1 --epin 0 --event True</p><p>This will use PIN11 (GPIO1) for output and toggle at 1 second. Pin13 will wait for Rising Edge trigger. If you connect both pins together then you will get:</p><p># python blink.py -chip gpiochip0 -opin 1 --epin 0 --event True<br />1970-01-01 00:47:21,419 DEBUG blink.py:60 - <module>() main<br />1970-01-01 00:47:21,420 DEBUG blink.py:66 - <module>() monitor<br />1970-01-01 00:47:21,421 DEBUG selector_events.py:59 - __init__() Using selector: EpollSelector<br />1970-01-01 00:47:21,424 DEBUG gpiowrapper.py:10 - __init__() args chip=gpiochip0 pin=1<br />1970-01-01 00:47:21,558 DEBUG gpiowrapper.py:16 - __init__() type <class 'gpiod.Chip'> <class 'int'><br />1970-01-01 00:47:21,648 DEBUG gpiowrapper.py:36 - __init__() type <class 'gpiod.Chip'> <class 'int'><br />1970-01-01 00:47:22,153 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:23,156 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:24,159 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:25,161 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:26,164 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:27,167 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:28,170 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:29,172 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:30,175 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:31,178 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:32,180 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:33,183 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:34,186 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:35,188 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:36,191 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:37,194 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:38,197 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:39,199 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:40,202 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:41,205 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1970-01-01 00:47:42,207 DEBUG gpiowrapper.py:57 - event_cb() event RISING EDGE<br />1<br /></p><p><br /></p>tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com2tag:blogger.com,1999:blog-585820012390048267.post-91867098530400874062020-08-30T20:23:00.003-07:002020-08-30T20:23:37.205-07:00Using FPGA to accelerate serial protocol handling adding two AXI Stream blocks. <p> I have been working on communication protocol to the CMOD-S7 and CYC1000 via the FTDI over USB. One of the issues is round-trip-time. Currently the packet handling is done all by the MicroBlaze. There are to basic packet handling duties the Microblaze performs in the RX/TX data path:</p><ul style="text-align: left;"><li>Stripping or adding ESC formatting. This loosely follows SLIP/PPP serial encoding. </li><li>Calculating CCITT CRC-16</li></ul> So, to lower the round trip time, I have been working on two independent AXI Stream blocks:<div><ol style="text-align: left;"><li>16 bit CRC, will calculate the CRC per byte when TLAST is raised append the two bytes.</li><li>Packet format: add SOP (start of packet byte), ESC any bytes that are SOP,EOP, or ESC and add EOP when TLAST is raised. </li></ol><p>Using just the MicroBlaze, the ping rate is 1.7Mpbs, adding the two AXI stream pushes the rate to 2.7Mbps.</p><p> </p><p>Here is a block diagram from vivado.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-nAnV4Q0yEpDeNWkKHWWYu2otmuNr2lAYvt2zNo_OxiOzDvkn282TTBGhtj3vnJC2oB2U25eQMDPzjTxnRuUTL4CcAbyqi7BrDcqzfJRk0wJPY5XN6LT8g0u7HmwVayGiTb1102Q8Xrb-/s3313/offloading.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="949" data-original-width="3313" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-nAnV4Q0yEpDeNWkKHWWYu2otmuNr2lAYvt2zNo_OxiOzDvkn282TTBGhtj3vnJC2oB2U25eQMDPzjTxnRuUTL4CcAbyqi7BrDcqzfJRk0wJPY5XN6LT8g0u7HmwVayGiTb1102Q8Xrb-/s640/offloading.png" width="640" /></a></div><br /> The next goal is to eliminate the MicroBlaze processor and add a AXI switch. The serial protocol has a ToPort, this will be used for the AXI Stream ID. <p></p><p>This project take some time, the goal is to push the data rate to 12Mbps, maybe add the ADC and temperature sensor, to also push data via AXI stream. <br /></p></div>tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-63697710327085383992020-08-23T10:44:00.005-07:002020-08-23T10:52:24.408-07:00Using AXI stream with DMA on a CMOD-S7 FPGA board<p>After a several weeks of tweaking, DMA driver and Verilog, AXI Stream serial TX/RX using DMA with the MicroBlaze soft core is working. <br /></p><p></p><p>Over the past several months I have been using Fast Serial mode with FTDI, but it is only half duplex, if the PC and FPGA try to send messages at the same time, the FTDI chip does some weird things depending on the state if the FDSI and FSDO, worked with tech support, "should only be used with a half duplex protocol". </p><p>So, back to standard serial, the FTDI serial interface can support 12Mbps in full duplex, so, it is possible to have the FPGA and PC send async messages. So, how to get 12 Mpbs to the Spartan 7?</p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUhAy3msPjn7-vK-kfYJeyp4nGpdaMYqXoo3HewO8A5TRJ88GF5i-UoaJvak7DLEWM9tSVPZfpQE2c8utmoFHHbYvBhXTBQ5qcr7RFtkacCvjB_SNSgtqCnB7c71IRs-1LLn6TsAsqIBsJ/s1868/axis.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1067" data-original-width="1868" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUhAy3msPjn7-vK-kfYJeyp4nGpdaMYqXoo3HewO8A5TRJ88GF5i-UoaJvak7DLEWM9tSVPZfpQE2c8utmoFHHbYvBhXTBQ5qcr7RFtkacCvjB_SNSgtqCnB7c71IRs-1LLn6TsAsqIBsJ/s640/axis.png" width="640" /></a></div><p>Created a axis_serial RTL (In verilog) that can stream TX/RX bytes out to the FTDI chip at 12Mpbs. This is a real simple block, used serial code from <a href="https://www.nandland.com/vhdl/modules/module-uart-serial-port-rs232.html">Nandland</a> with a AXI stream wrapper. Also this wrapper looks at the incoming bytes from the serial and will raise TLAST for EOP (End of packet) byte. TLAST is connected to the DMA block and this will terminate the DMA and the RX buffer is now filled with a packet. </p><p>The DMA driver is packet based, i.e. like Ethernet LWIP example, but in this case it is using a serial stream. This way the microbalze is not processing serial interrupts per byte, but, interrupt per packet. </p><p>Configured the clock to be 120Mhz, the current "ping rate" is 1.7Mpbs in one direction, or 3.4Mpbs full duplex. I'm working on offloading the CRC and packet ESC packing to the FPGA. CRC is done, Packing is taking some time. This will be in the TX direction for now, so, the rate should increase to 3.4Mbps in TX direction.</p><p>All of the code is in <a href="https://github.com/tcmichals/CMODS7/tree/master/axi_dma_stream_microblaze">gitub</a>. <br /></p><p><br /></p><p><br /></p><p><br /></p>tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-80016107948713564992020-05-24T07:37:00.002-07:002020-05-24T07:42:25.956-07:00Using SERV RISCV soft processor on CYC1000 FPGA board<div>I've been working on using a FPGA for I/O acceleration for low cost ARM boards for a while. The first pass was done using standard Avalon bus master over Fast Serial interface using the FTDI chip. Fast serial can use up to 50Mhz clock, but it was scale back to around 20Mhz for debugging with my old logic analyzer. <br /></div><div><br /></div><div></div><div>The goal is to use HighSpeed USB between a low end ARM SBC and off load tasks like:</div><div><ul style="text-align: left;"><li><a href="https://www.hackster.io/MichalsTC/decoding-pwm-using-an-fpga-7c4efa">Decoding PWM RC transmitter</a></li><li><a href="https://www.hackster.io/MichalsTC/speed-control-of-a-bldc-motor-with-an-esc-and-fpga-via-usb-8802c2">DSHOT150</a></li><li>APA102 LED bar<br /></li></ul></div><div><br /></div><div>Recently, I moved to using fusesoc tool and the SERV RISV processor for offloading some of the verilog coding effort. So, far the project SERV RISCV is running, fast serial wishbone interface has been debugged. Next is to update the protocol. The project is on <a href="https://github.com/tcmichals/quad-serv-riscv">github</a>. Soon to follow a HacksterIO article</div><div><br /></div><div>Using the <a href="https://content.riscv.org/wp-content/uploads/2019/06/12.15-SERV-Zurich-Copy.pdf">SERV</a> processor is SMALL, and can use several in this design, will use one for the accelerometer control. <br /></div><div><br /></div><div><br /></div>tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-24811667807983968242020-03-15T10:54:00.003-07:002020-03-18T10:39:59.646-07:00PWM input is working (Betaflight and CYC1000)Made some good progress on integrating CYC1000 FPGA into betaflight running on Linux. The CYC1000 is a FPGA performing PWM decode (from cheap RC transmitter), PWM encode (oneshot125 or DSHOT), APA102 led strip and on board LED. Updated betaflight to send requests to CYC1000 to read PWM registers via libftdi1 over USB. <br />
<br />
Here is a <a href="https://youtu.be/tpeyc9LSBoo">youtube</a> video of betaflight showing PWM decode and IMU. tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-21070098534446621232020-02-25T18:57:00.001-08:002020-02-26T06:20:15.352-08:00Using Fast Opto-Isolated Serial Interface Mode in the FT2232H with CYC1000 FPGA and libftdi1After learning more about FPGA programming i.e verilog, nmigen, migen, and generating test benches finally got back on finishing the Avalon bus for the quad-copter.<br />
<br />
The core gateware is Avalon bus with slave PWM (oneshot125), DSHOT150, slave LED APA102, slave on board LED, slave PWM decoder, and general timer. The master is using Avalon bus master bytes to packet interface over Fast Opt-Ioslated Serial interface. One of the issues I was having was how to communicate from Linux to the CYC1000 board, could do standard serial, the top speed is 2Mbps, so, took the time and implemented Opt-Isolated serial interface at 25Mbps. Reading more about the interface it is half duplex, but, it is still faster than serial. <br />
<br />
So, use the standard FTDI driver with Linux with standard tty termios, but after trying to get 1ms round trip packet processing, the CPU usage was high and still slow. I tried setting setserial /dev/ttyUSB0 low_latency, that helped but still high CPU usage.<br />
<br />
Next was trying libftdi1, with a latency timer of 0. After a few few mod's to libftdi1, using a 100us timer to generate packets and uses 40% CPU usage. Validated the data stream using LA2016 Logic Analyzer and the rrt is 180us. So, not bad. Next is to move everything on to the orangePI plus2 H5.<br />
<br />
<br />
<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-83463574484479703352020-02-08T10:58:00.001-08:002020-02-08T18:27:59.061-08:00First project on Hackster.io<a href="https://www.hackster.io/">Hacksterio</a> hosted webinar "<a href="https://events.hackster.io/mini-but-mighty">Mini but Mighty: Motor control Live Build with MiniZed</a>" also Avnet/Hacksterio/Xilinix created a design challenge. After several days of work, entered with a <a href="https://www.hackster.io/MichalsTC/mini-but-mighty-motor-control-via-builtin-accelerometer-221619">project</a> on Hacksterio. Will find out on 2/18 on the results. tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-89012244139400777672020-01-08T18:19:00.000-08:002020-01-22T17:45:59.399-08:00PWM encode/decode is working using a FPGATested FPGA based pwm encode/decode. Using Hobby King HK-16A V2 6 channel transmitter and decoding 6 channels of PWM from the receiver.. Encoding 4 PWM with a 1-2ms pulse width to 4 ESCs. The biggest issue generating PWM is to complete the last cycle before apply the next update. <br />
<br />
Next step is to integrate into BetaFlight Linux Port, the goal is to be flying in a month.<br />
<br />
All the code is on <a href="https://github.com/tcmichals/cyc1000">github</a>. <br />
<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-91070025797479611752020-01-05T18:32:00.000-08:002020-01-05T18:35:56.618-08:00New logic analyzerIt was time to update to a better logic analyzer, <a href="https://www.seeedstudio.com/LA2016-Logic-Analyzer-p-2218.html">LA2016</a>. I have been using 8 channel original saleae. The LA2016 is a lot faster, 200Mhz and has internal storage with advance triggering.<br />
<br />
One of the biggest issues I've been running into is tracing fast digital signals when developing FPGA code. CYC1000 uses Cyclone 10LP FPGA, have used Quartus internal logic analyzer a couple of times to trace/debug designs. But, I still like to have one around, so, the LA2016, so far it has been very handle, with a 1Mhz signal with a pulse width of 15ns was not an issue. But, also still getting up to speed on Verilog, have been working on test benches and verilator C++ test code. This way modeling and formal verification should cover most of the issues I've having debugging designs. <br />
<br />
While debugging PWM state machine, the power supply driving my ESC tripped on overload. No, it does not power one, so, have another one on order, 12v 10amp. So, will be a little more careful.<br />
<br />
Looks, like the PWM output should be working now, there was a glitch when setting a new PWM value, the duty cycle was going to 80% causing some ESC to stop.<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-6467889936441799332019-12-24T19:35:00.003-08:002019-12-24T19:35:36.311-08:00CYC1000 decoding PWM Finally got back to CYC1000 board, been working on C++ interface to fast serial with the FTDI and FPGA, its working at 20Mpbs via USB. The biggest issue was getting TTY to respond faster that 10ms. So, on Linux one simple way is to use setserial command for low latency, i.e.<br />
setserial /dev/ttyUSB0 low_latency<br />
<br />
Now, it is possible to process receive/transmit faster then 10ms. So, using Avalon Master, able to send Read/Write commands at a maximum round trip of 2ms. The issue is still Linux, at the FPGA measure 2us round trip (send/process/transmit)<br />
<br />
Connected up my old HK-T6A receiver to the CYC1000 and able to decode 6 channels of PWM and send back to the PC at 10ms. It takes 20ms for the HK-T6A to cycle over the 6 channels. So, 10ms is a good poll rate. <br />
<br />
One way to get rid of polling is to use a Avalon stream and send PWM with out sending a read request.<br />
<br />
So, the next step is to get PWM generation complete then should be ready to merge with Linux based BetaFlight. See how responsive it is. <br />
<br />
I was able to add a transistor on the Orange PI Zero Plus2 so, now the H5 is running at 1.7Ghz per core without throttling. The goal is to have BetaFlight running and sending packets to the FPGA at 400Hz. <br />
<br />
Might have to go around tty and use to the FTDI API. But, I might ditch the how project and use a Zynq processor. <a href="http://www.chinaqmtech.com/xilinx_zynq_soc">Maybe the QMTECH board</a>. Maybe some can send me one ;) Instead of using USB, now just have PWM encode/decode in the FPGA block. I have a DSHOT written, but, first simple PWM. Then, move to DHSOT once the latency of 2ms can be reduced to 300us or so. <br />
<br />
I'm still working on ditching Avalon and moving forward to use a RISC-V processor to serialize/de-serialize packets. I'm thinking of trying the SweRV Core EL2, for size and simplicity. <br />
<br />
<br />
<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-62586837188589304002019-11-25T18:43:00.000-08:002019-11-25T18:43:32.586-08:00Remote debugging via GDB using VSCodeSlowly making progress on getting Betaflight working on Linux on an orange PI zero-plus2 board. <br />
<br />
During porting I've been using VSCode, it is a nice tool works on Linux and Windows. Also, with some configuration allows me to xcross debug Betaflight via gdb on the orange PI board.<br />
<br />
How is this done? First need to create a configuration to start the gdb on the host, in my case it is Ubuntu running on x86 processor. Here is the launch.json:<br />
<br />
<div style="background-color: #1e1e1e; color: #d4d4d4; font-family: 'Droid Sans Mono', 'monospace', monospace, 'Droid Sans Fallback'; font-size: 14px; font-weight: normal; line-height: 19px; white-space: pre;">
<div>
<span style="color: #d4d4d4;"> {</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"name"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"C++ Launch gdbserver"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"type"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"cppdbg"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"request"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"launch"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"program"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"${workspaceRoot}/obj/main/betaflight_LINUX.elf"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"miDebuggerServerAddress"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"192.168.1.20:9091"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"args"</span><span style="color: #d4d4d4;">: [],</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"stopAtEntry"</span><span style="color: #d4d4d4;">: </span><span style="color: #569cd6;">true</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"cwd"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"${workspaceRoot}"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"environment"</span><span style="color: #d4d4d4;">: [],</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"externalConsole"</span><span style="color: #d4d4d4;">: </span><span style="color: #569cd6;">true</span><span style="color: #d4d4d4;">,</span></div>
<br /><div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"linux"</span><span style="color: #d4d4d4;">: {</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"MIMode"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"gdb"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"miDebuggerPath"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"aarch64-linux-gdb"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> },</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"osx"</span><span style="color: #d4d4d4;">: {</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"MIMode"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"gdb"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"miDebuggerPath"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"aarch64-linux-gdb"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> },</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"windows"</span><span style="color: #d4d4d4;">: {</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"MIMode"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"gdb"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> </span><span style="color: #9cdcfe;">"miDebuggerPath"</span><span style="color: #d4d4d4;">: </span><span style="color: #ce9178;">"aarch64-linux-gdb"</span><span style="color: #d4d4d4;">,</span></div>
<div>
<span style="color: #d4d4d4;"> }</span></div>
<div>
<span style="color: #d4d4d4;"> }</span></div>
</div>
<br />
So, this will is the aarch64-linux-gdb that was compile using build root and the ARM target file Betaflight_LINUX.elf file.<br />
<br />
On the target, Orange PI Zero plus 2, I use ssh to start a gdbserver session. Using the following command: # gdbserver :9091 obj/main/betaflight_LINUX.elf <br />
<br />
this allows the host to attach to gdbserver to debug the app on the target. <br />
<br />
I use rsync to copy changes from x86 to orange pi. So, after finding the issue, edit the code using VSCode, cross compile, rsync the start gdbserver. <br />
<br />
I was going to add ssh to the launch, but, I tend to forget to do rysnc. Post any questions.<br />
<br />
Oh, using gdb and VSCode allows you to set break points in SRC and debug on the remote target. Nice, the only issue is restarting a debug session requires you to manually restart gdbserver on the target. <br />
<br />
If you have questions let me know. Right now debugging why IMU is not being found using SPI. <br />
<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-12967331344434377372019-08-04T18:04:00.002-07:002019-08-04T18:04:27.703-07:00CYC1000 example using Python and Fast Serial.Updated the github for <a href="https://shop.trenz-electronic.de/en/TEI0003-02-CYC1000-with-Cyclone-10-FPGA-8-MByte-SDRAM">CYC1000</a> project (example_project). The project has the following features:<br />
<ul>
<li>Uses Serial port using Avalon byte protocol to access the Avalon master.</li>
<li>The Serial port is using the FTDI Fast serial mode, the FGPA Clock is 12Mhz, so the bus is running at 6mhz. </li>
<li>Mapped two Avalon slaves:</li>
<ul>
<li>LEDs</li>
<li><a href="https://shop.pimoroni.com/products/blinkt">APA102 Blinkt LED bar</a></li>
</ul>
</ul>
The Python example is able to toggle either the on board LED or the Blinkt LED bar.<br />
<br />
Moving forward to PWM decode. <br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-52914719991236763342019-03-31T10:56:00.001-07:002019-11-24T08:08:21.143-08:00Fast Serial FTDI CYC1000 FPGA boardFinally have a simple demo using 50Mhz receive working between the FTDI and Cyclone 10LP (CYC1000 FPGA board)<br />
<br />
The goal of this project is to have USB serial working at 50Mhz (TX/RX) and have simple protocol to abstract SPI, PWM decode/encode, OneShot peripherals.<br />
<br />
The simple demo shows the RX character value on the LEDs. <br />
<br />
Steps:<br />
<ol>
<li>git clone https://github.com/tcmichals/cyc1000.git</li>
<li>start Quartus</li>
<li>open the fast_serial_test project</li>
<li>compile and load</li>
<li>start minicom --device /dev/ttyUSB0 </li>
<li>edit the serial port to remove hardware hardware handshaking. It does not matter what the baud rate is. Just start typing and the LEDs will change values to the RX chacaters. The easiest is to use '0', '1' '0' is 0x30 then 1 is 0x31, so only one LED changes. </li>
</ol>
<br />
Also, must change the EEPROM of the FPGA to use opt serial. For this to work.<br />
<br />
More to come. Next is TX. <br />
<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com1tag:blogger.com,1999:blog-585820012390048267.post-43552143081309866162019-03-17T18:19:00.000-07:002019-03-17T18:19:23.087-07:00Fast Serial mode FTDI (CYC1000)Making progress on getting fast serial mode working on the CYC1000. The first step was to create some verilog code to route signals out to a header to validate the data using a saleae Logic Analyzer, also generate a clock.<br />
<br />
Configured port B to opto-ioslate and keep the driver virtual serial port. This allows Linux to standard serial over USB but the FTDI converts the serial stream into fast serial using the mpsse. <br />
tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-49324443448404297602019-02-13T19:26:00.001-08:002019-02-13T19:26:16.543-08:00Learning Verilog with the CYC1000Finally getting comfortable writing some basic verilog code to walk the LEDs on the CYC1000 FPGA board.<br />
<br />
I started with using Quartus WIN10 VM (using VirtualBox) and moved to Linux with Quartus 18.1 Build 625. Had to over come a couple of basic issues with Quartus on Linux:<br />
<ol>
<li>Renamed /quartus/linux64/libstdc++.so to ./quartus/linux64/libstdc++.so.old for some reason, the library paths are not right when loading, will look at the more in the future.</li>
<li>Some of megafunctions lock up, so, resize the dialog before moving to the next option or entering any values.</li>
</ol>
I have not tried in simulation, but compiling, loading to SPI Flash or to the FPGA works fine.<br />
<br />
The first example was a simple <a href="https://github.com/tcmichals/cyc1000">walking LED</a> and has a loopback for the RS232 for the FTDI chip.<br />
<br />
The CYC1000 is connected to the Channel A and B of the FTDI FT2232H. Channel A, is for JTAG and Channel B is RS232/HighSpeed Serial/Or SPI.<br />
<br />
To get /dev/ttyUSB0 working, need to change the 51-arrow-programmer.rules to remove deleting the serial interface.<br />
<br />
# Interface number zero is a JTAG.<br /># SUBSYSTEM=="usb",\<br /># ATTRS{idVendor}=="0403",\<br /># ATTRS{idProduct}=="6010",\<br /># ATTR{interface}=="Arrow USB Blaster",\<br /># ATTR{bInterfaceNumber}=="00"<br /># RUN="/bin/sh -c 'echo $kernel > /sys/bus/usb/drivers/ftdi_sio/unbind'"<br />
<br />
The end project is to use the protocol over the serial interface over USB to control:<br />
<ul>
<li>SPI Master</li>
<ul>
<li><a href="https://shop.pimoroni.com/products/blinkt">Controlling a LED strip</a></li>
</ul>
<li>6 channel PWM decoder</li>
<li>4 channels of OneShot 150/42</li>
<li>4 channels DSHOT</li>
<li> I2C A/D converter </li>
</ul>
The RS232 loopback is working at 3Mbps using minicom. The next project will be getting a Serial RX/TX/FIFO working. <br />
<br />
<br />
<br />
<br />
<br />
<br />
tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-6207912760145185212018-08-08T06:40:00.002-07:002018-08-08T06:53:15.090-07:00New FPGA boardsI'm constantly looking for new SBC and FPGA boards. Here are a couple links:<br />
<br />
<ul>
<li><a href="https://www.kickstarter.com/projects/alchitry/alchitry-digital-design-simplified/description">Alchitry: Digital Design Simplified Xilinx <span style="background-color: white; color: #282828; font-family: "maison neue book" , "helvetica neue" , "helvetica" , "arial" , sans-serif; font-size: 16px;">Artix 7 XC7A35T-1C </span> and iCE40 </a></li>
<li><a href="https://store.digilentinc.com/cora-z7-zynq-7000-single-and-dual-core-options-for-arm-fpga-soc-development/">Cora Z7-10 Z7-07S Zynq boards </a></li>
<li><a href="https://store.arduino.cc/usa/arduino-vidor-4000">MKR Vidor 4000 board</a></li>
<li><a href="https://shop.trenz-electronic.de/en/TEI0003-02-CYC1000-with-Cyclone-10-FPGA-8-MByte-SDRAM?c=480">CYC1000 with Cyclone 10 FPGA, 8 MByte SDRAM</a></li>
<li><a href="https://shop.trenz-electronic.de/en/Products/Trenz-Electronic/MAX1000-Intel-MAX10/">MAX1000</a></li>
<ul>
<li>If local to US <a href="https://www.arrow.com/en/products/max1000/arrow-development-tools">Arrow</a> also stocks this board. </li>
</ul>
<li>SBC</li>
<ul>
<li>Renegade Elite</li>
<ul>
<li><a href="https://www.indiegogo.com/projects/renegade-elite-the-revolutionary-mini-computer-computers-pc/x/19050289#/">RK3399 Rock chip processor. Quad-core A53 and Dual-core A72.</a></li>
</ul>
</ul>
</ul>
tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-17087086839487595852018-01-20T12:50:00.000-08:002018-01-20T18:04:38.140-08:00Xilinx and MiniZed boardFinally have a simple demo running on the PL (programmable logic) blinking the Red and Green LED.<br />
<br />
Getting up to speed using Zync-7000 and Vivado (GUI) tool takes some time to get up to speed on. Several weeks ago I took the the <a href="http://zedboard.org/support/trainings-and-videos">SpeedWay</a> class, that was a great way to get an overall overview and help get a start on the <a href="http://zedboard.org/product/minized">MiniZed</a> board.<br />
<br />
Here is the led.c verilog (yes simple)<br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />module led<br />#( <br /> parameter WIDTH = 24<br /> )<br /> (<br /> input wire Clk, <br /> input wire Reset,<br /> output LED_G,<br /> output LED_R<br /> );<br /> <br /> integer counter = 0;<br /> reg LED_G_reg=0;<br /> reg LED_R_reg=0;<br /> <br /> assign LED_G = LED_G_reg;<br /> assign LED_R = LED_R_reg;<br /><br /> always @(posedge Clk) begin<br /> /* if (Reset ==1 ) begin<br /> counter <= 0;<br /> LED_R_reg <=0;<br /> LED_G_reg <=0;<br /> end<br /> else */begin<br /> <br /> counter <= counter+1;<br /> LED_R_reg <= counter[23];<br /> LED_G_reg <= ~counter[23];<br /> end <br /> end<br /><br />endmodule</span><br />
<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: inherit;">Some tips</span></span><br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">Linux with Wayland causes Vivado crash. To work around this use X, hope they will <a href="https://itsfoss.com/switch-xorg-wayland/">fix</a> it.</span></li>
<li>Using a constraint file you must declare the output on the net list. If not the block will not be generated.</li>
<li>The Zynq PS clocks are used to drive the PL, so, must have a simple ARM program or init script to start the clocks.</li>
<li>The <a href="http://zedboard.org/product/minized">MiniZed</a> board is nice to use, low cost and has a lot of features to start learning FPGA or ARM (Linux or RTOS(FreeRTOS)) </li>
</ul>
I can do a simple hello tutorial if requested.<br />
<br />
Next steps:<br />
<ol>
<li>Create a SWO trace/Serial Wire Viewer (SWV) demo on STM32 use using debug messages. Validate it is working using a logic anaylzer </li>
<li>Create FPGA code to decode the Manchester bit stream and send it via DMA to the ARM-9 Cortex on the </li>
</ol>
<br />
<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-9230439352952230882017-12-23T15:50:00.000-08:002017-12-23T15:50:13.808-08:00FreeRTOS trace HW/SW with nw.js applicationWhile working on CleanFlight Linux with a I/O micro-controller for extra peripherals, there is no straight forward way to get performance, trace, and general information about the state of the firmware on the micro-controller.<br />
<br />
<br />
Goal:<br />
<ul>
<li>Provide an open source solution to get metrics on the firmware using <a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0314h/Chdgcbbg.html">traceSWO port</a>.</li>
</ul>
Implementation: <br />
<ul>
<li>Use FreeRTOS trace messages and send them out one of the channels of SWO port </li>
<li>Also allow setting ETM tracing</li>
<li>Create a GUI (nw.js) and command line tools to parse and show trace data from FreeRTOS</li>
<ul>
<li>GUI will show live line/bar charts of Task performance and I/O</li>
<li>python tools to parse/mine data allows custom reports.</li>
</ul>
</ul>
<br />
I have severa<a href="http://wiki.stm32duino.com/index.php?title=GD32F103C8_mini">l GD32F103C8 red boards</a>, use these to decode the SWO and send trace information to nw.js application. <br />
<br />
Thoughts? suggestions? tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-81936128463097821122017-12-21T20:32:00.002-08:002017-12-21T20:38:56.057-08:00Cleanflight port to Linux (LinuxFlight) statusCreated a new CLI (command Line Interface) module based on C++ and uses msgProtocol for subscribing/publishing messages. This allows components (bash shell) or transports (UDP/TCP (Configurator)) to use the CLI at the same time. So, now one instance of CLI can process messages from anywhere. For example: Linux has bash shell so, it would be nice not to startup Configurator to get basic info. Use the bash shell<br />
<br />
Here it is:<br />
LinuxFlight>help<br />
status - show status<br />
help<br />
tasks - show task stats<br />
version - show v<br />
LinuxFlight>status<br />
<br />
System Uptime: 274 secondsVoltage: 0 * 0.1V (0S battery - NOT PRESENT)CPU Clock=500MHz, GYRO=MPU9250, ACC=MPU9250, MAG=AK8963<br />
Stack size: 790724, Stack address: 0xc10b0CPU:0%, cycle time: 23226, GYRO rate: 43, RX rate: 282, System rate: 10Arming disable flags: TH<br />
LinuxFlight>tasks<br />
<br />
<tt>
LinuxFlight>tasks</tt><span style="font-size: xx-small;"><span style="font-family: "Courier New", Courier, monospace;">Task list rate/hz max/us avg/us maxload avgload total/ms<br />00 - ( SYSTEM) 10 3 1 0.5% 0.5% 0<br />01 - ( PID) 444 22177 523 985.1% 23.7% 1270<br /> - ( GYRO) 889<br />02 - ( ACCEL) 997 21337 723 2127.7% 72.5% 1822<br />03 - ( ATTITUDE) 99 327 14 3.7% 0.6% 5<br />04 - ( RX) 143 166 36 2.8% 1.0% 9<br />05 - ( SERIAL) 101 87 4 1.3% 0.5% 1<br />08 - (BATTERY_CURRENT) 149 41 2 1.1% 0.5% 0<br />09 - ( BATTERY_ALERTS) 4 7 2 0.5% 0.5% 0<br />10 - ( GPS) 99 129 6 1.7% 0.5% 2<br />11 - ( COMPASS) 39 22825 756 89.5% 3.4% 158<br />14 - ( TELEMETRY) 255 39 2 1.4% 0.5% 0<br />15 - ( LEDSTRIP) 101 2522 74 25.9% 1.2% 30<br />RX Check Function 0 0 0<br />Total (excluding SERIAL) 3239.9% <br />LinuxFlight></span></span><br />
<br br="" />
<br />
Next is to get the battery voltage reporting and figure out the issue with the loading.<br />
<br />
Might have to try the RT kernel but, first load LinuxFlight on to its own processor. Also, might have to remove CPUFREQ it is known to impact realtime performance.<br />
<br />
<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-62516870578527109252017-12-16T20:01:00.000-08:002017-12-16T20:01:15.641-08:00CleanFlight on Linux using micro-controller for PWM/LCDFinally have micro-controller sending PWM from a HK-T6A to Linux version of CleanFlight. <br />
<br />
Created a new protocol (protocolMsg), allowing to route messages between software components over UDP or within the app via message bus.<br />
<br />
For example, CleanFlight has a PWM parallel RX IO software block and PWM RX driver block. The PWM RX driver block was replaced with a PWM client protocolMsg handler, the micro-controller is a PWM server protocolMsg handler. The messages are routed via UDP over USB. <br />
<br />
The goal is to update CleanFlight CLI and msp to handle message processing from multiple transports, i.e. serial, UDP, TCP. <br />
<br />
<br />
CleanFlight Configurator is proper showing receiver status. USB/UDP is running at 28Kb/s for RPM messages. <br />
<br />
To Do list:<br />
<ul>
<li>validate new Linux serial driver</li>
<ul>
<li>a simple libevent shim (same as UDP/TCP shim)</li>
<li>used for GPS </li>
</ul>
<li> validate new lcdStrip Shim</li>
<ul>
<li>allows routing LCD strip messages (LED RGB) to be routed to micro-controller.</li>
</ul>
<li>write dshot shim</li>
<ul>
<li>allow sending sdhot motor messages to micro-controller</li>
</ul>
</ul>
tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-679972336735683582017-10-22T08:05:00.001-07:002017-10-22T08:31:36.948-07:00OrangePI Zero overlay and uboot/armbianThe Armbian has good documentation about how to use device overlays for their uboot scripts. I wanted to dive a little deeper and understand some of the basics and still use buildroot.<br />
<br />
Boot process of uboot, there is a file on the FAT partition boot.src, this is a binary file generated by mkimage. The source file is in board/orangepi/orangepi-zero boot.sh:<br />
setenv fdt_high ffffffff<br />
setenv load_addr "0x44000000"<br />
echo "Boot script loaded from ${devtype}"<br />
<br />
setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait<br />
<br />
fatload mmc 0 $kernel_addr_r zImage<br />
fatload mmc 0 $fdt_addr_r sun8i-h2-plus-orangepi-zero.dtb<br />
fdt addr ${fdt_addr_r}<br />
fdt resize 65536<br />
setenv processorName sun8i-h3-<br />
setenv overlays i2c0 spi-spidev<br />
for overlay_file in ${overlays}; do<br />
echo " looking for ${processorName}${overlay_file}.dtbo"<br />
if fatload mmc 0 ${load_addr} ${processorName}${overlay_file}.dtbo; then<br />
echo "Applying user provided DT overlay ${overlay_file}.dtbo"<br />
fdt apply ${load_addr} || setenv overlay_error "true"<br />
fi<br />
done<br />
<br />
<br />
bootz $kernel_addr_r - $fdt_addr_r<br />
<br />
So, what happens is the device tree overlays are merged in uboot with the dtb file loaded for the board using fdt command line tools. This allows to change the board dtb without always recompiling it.<br />
<br />
Post any questions you have. So, spi and i2c are now using device tree overlays.<br />
<br />
Here is the overlay for SPI:<br />
/dts-v1/;<br />
/plugin/;<br />
<br />
/ {<br />
compatible = "allwinner,sun8i-h3";<br />
<br />
fragment@0 {<br />
target-path = "/aliases";<br />
__overlay__ {<br />
spi0 = "/soc/spi@01c68000";<br />
spi1 = "/soc/spi@01c69000";<br />
};<br />
};<br />
<br />
fragment@1 {<br />
target = <&spi0>;<br />
__overlay__ {<br />
<br />
#address-cells = <1>;<br />
#size-cells = <0>;<br />
status = "disabled";<br />
<br />
spidev@1 {<br />
compatible = "linux,spidev";<br />
reg = <0>;<br />
spi-max-frequency = <1000000>;<br />
};<br />
};<br />
};<br />
<br />
fragment@2 {<br />
target = <&spi1>;<br />
__overlay__ {<br />
<br />
#address-cells = <1>;<br />
#size-cells = <0>;<br />
status = "okay";<br />
<br />
spidev@2 {<br />
compatible = "linux,spidev";<br />
reg = <0>;<br />
spi-max-frequency = <25000000>;<br />
};<br />
};<br />
};<br />
};<br />
<br />
<br />
so, this completes the task of using overlays. Next DHCP and zeroconfig.<br />
<br />
Also, have a modification to EEM USB handler, to improve performance. Also, thinking of adding a way to use several packets at once based on the size of the packet.<br />
<br />
<br />
<br />
<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com7tag:blogger.com,1999:blog-585820012390048267.post-36468665223856198272017-10-15T20:47:00.002-07:002017-10-15T20:47:56.293-07:00Merge latest changes from CleanflightUpdated the repo with the latest CleanFlight changes, the merge compiled and ran on x86. I'm in the middle of updating OrangePI buildroot to use some patches from Armbian and start using device tree overlays. This makes it easier to add I2C etc without changing the orangePI zero DTS. More on that in the next couple of posts. i.e basic device overlays using uboot via fdt commands.<br />
<br />
Cleanflight configurator is working, the imu processing was not enabled, so, now the graphic is now updating. <br />
<br />
Also move the process to a core, using cpu isolation (via taskset, etc) to reduce jitter. <br />
<br />
Also, working on using dnsmasq as a dhcp server with mdev, this allows I/O board to get a IP address and try zeroconfig/DNS-Based Service Discovery. The goal is to use names, instead of hard coded IP addresses, so when moving to WiFi networking there will not be a conflict. Confusing? I'm too ;)<br />
<br />
Updated the I/O EEM packet handling to increase the performance, takes about 23us per 64 byte USB packet. The goal is to have a 512 UDP packet take less then a 1ms. <br />
<br />
Looked at the GPS handling, right now, GPS parsing is handled on the I/O card, tho goal being to reduce processing in the main loop. Still looking at the code and how RTH and stabilization process the GPS information.<br />
<br />
Tasks Order:<br />
<ul>
<li>Update Kernel/u-boot to use overlays</li>
<ul>
<li>4.13 kernel is booting along with u-boot (Now)</li>
<li>updating boot.src to process device tree overlays (in progress)</li>
</ul>
<li>Dynamic IP addressing </li>
<ul>
<li>Test DHCP server first</li>
<li>Add zeroconfig with MDNS on lwIP </li>
<li> </li>
</ul>
<li> Retest EEM USB Ethernet</li>
<li>Add LED API </li>
<ul>
<li>Cleanflight uses two LED APIs will use the basic one, i.e 3 LEDs and test the speed of UDP updating LEDs from Linux</li>
</ul>
<li>Add PWM reciever API</li>
<ul>
<li>The I/O is processing PWM from receiver, will forward this info onto Cleanflight validate the configurator is working. </li>
</ul>
</ul>
tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0tag:blogger.com,1999:blog-585820012390048267.post-359995557726411072017-09-17T20:13:00.001-07:002017-09-18T06:41:56.677-07:00Cleanflight repo updated with OrangePI Zero Flight ControllerUpdated https://github.com/tcmichals/cleanflight repo with current code for the OrangePI flight controller.<br />
<ul>
<li>Replaced the cleanflight scheduler with libevent</li>
<ul>
<li>all timers are based on libevent timers</li>
<li>in process of adding events for:</li>
<ul>
<li>serial port</li>
<li>sockets</li>
<li>remote transmitters</li>
</ul>
<li>Instead of using hard timers for the above events, timer is more of a timeout/guard. The event, will be posted to wake up the task instead of a timer/poll event. </li>
<li>For logging this will be moved into another thread using a message So, sdcard write will not delay main processing loop, </li>
</ul>
</ul>
Adding exti (external gpio interrupts). Creating separate read file descriptors for each IO then push each one to libevent. This way, when IO triggers libevent will dispatch the proper handler. See if 4Khz is possible. <br />
<br />
using top:<br />
143 134 root S 5804 1% 0% ./obj/main/cleanflight_LINUX.elf<br />
<br />
Also added a command allowing to get basic info:<br />
<br />
<span style="font-size: x-small;">Task list rate/hz max/us avg/us maxload avgload total/ms<br />00 - ( SYSTEM) 10 2 1 0.5% 0.5% 0<br />01 - ( PID) 50 151 125 1.2% 1.1% 96<br /> - ( GYRO) 101<br />02 - ( ACCEL) 101 140 120 1.9% 1.7% 95<br />03 - ( ATTITUDE) 101 5 2 0.5% 0.5% 1<br />04 - ( RX) 50 18 10 0.5% 0.5% 4<br />05 - ( SERIAL) 101 12 2 0.6% 0.5% 1<br />06 - ( DISPATCH) <br />07 - (BATTERY_VOLTAGE) <br />08 - (BATTERY_CURRENT) 50 1 0 0.5% 0.0% 0<br />09 - ( BATTERY_ALERTS) 4 4 1 0.5% 0.5% 0<br />10 - ( GPS) <br />11 - ( COMPASS) <br />12 - ( BARO) <br />13 - ( ALTITUDE) <br />14 - ( TELEMETRY) 101 1 1 0.5% 0.5% 0<br />15 - ( RCSPLIT) <br />RX Check Function 0 0 0<br />Total (excluding SERIAL) 6.1% 5.3%<br />LinuxFlight></span><br />
<br />
I have to look into why some of the numbers a little high for PID and ACCEL. Also add memory locking and add high FIFO scheduling. But, looking good. <br />
<br />
<br />tcmichalshttp://www.blogger.com/profile/05764655304666199297noreply@blogger.com0