tag:blogger.com,1999:blog-37479703060276914322024-03-13T07:24:42.817+01:00Forty-Two, and now?Philosophy, technology (microcontrollers and geek stuff) and whatever I like.Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.comBlogger89125tag:blogger.com,1999:blog-3747970306027691432.post-2930745627620208752017-12-07T09:19:00.001+01:002017-12-07T17:28:23.302+01:00Many different cryptocurrenciesLooks like my <a href="https://fortytwoandnow.blogspot.ch/2017/12/making-sense-of-cryptocurrencies.html" target="_blank">last post</a> about the basic of cryptocurrencies sparked some attention, as I am writing 1 (one!) Bitcoin is trading around 14K USD and the % increase since the beginning of the year is astronomical, so that might be a good part of the reason.<br />
<br />
However there are many different cryptocurrencies and, while they all share the basic concepts, they are designed in slightly different ways which, by designs, affects their market.<br />
<br />
They all have a blockchain as described in my <a href="https://fortytwoandnow.blogspot.ch/2017/12/making-sense-of-cryptocurrencies.html" target="_blank">previous article</a>, they have wallets, miners etc.<br />
Some were created with slightly different goals in mind, but the main differentiation is how the mining is done.<br />
<br />
To understand how we got here, we need to see what happened with Bitcoin.<br />
<br />
At the beginning coding the software for the mining process was pretty much standard, it would involve some (most likely) C routine to run in the most common operating systems (Windows, Linux, MacOs etc).<br />
This routine would use the CPU to run the loop and calculate the hashcodes.<br />
It worked, but then we quickly realized that common CPUs have 4 cores, meaning they can run 4 routines in parallel, and moved to a multi threaded approach, this allowed to run the routine at the same speed, but 4 times at a time.<br />
<br />
By design all these algorithms must be relatively simple to compute because we need many iterations to find the solution to the puzzle (finding the correnct nonce), but it should be quick to verify the correctness of such nonce, else it would generate a lot of work on non-miners.<br />
<br />
Let me expand on this.<br />
Say that on average you need to run a loop 10.000 times before you can find the solution.<br />
Veryfying such solution would require one single iteration, therefore 1/10.000 time of the mining process.<br />
Typically, when you mine, you are fed with a number of tasks by "the network" (normally a mining pool) and then you dispatch back the solution.<br />
The pool must verify all your solutions, and also all the solutions of the other peers connected to the pool, therefore the verification process must be fast.<br />
<br />
Finally this boils down to the fact that we need a computation which is relatively simple, but can be executed many times in order to mine.<br />
<br />
This is the best scenario for parallel computing : simple tasks to be executed many times.<br />
<br />
Turns out that modern VGA cards have processosrs (GPU) very well equipped for that : their cores are way less sophisticated than those that we have in our main CPU, however they are good enough to run those basic calculations.<br />
<br />
Probably the most desired card for mining at the moment is the <a href="https://www.nvidia.com/en-us/geforce/products/10series/geforce-gtx-1080-ti/" target="_blank">NVIDIA GTX 1080 TI</a> , and to put things in perspective, this card has 3.584 Cores (@1.48GHz) while a normal PC CPU usually has 4 cores (@2 to 4 GHz).<br />
<br />
So, the GPU cores are still slower than the main CPU cores, but you get PLENTY of them, plus it is possible (with dedicated motherboards) to install 8 of them on a single PC, that makes 28K+ cores!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3WyWQJFJjWI_ftw7fBf7fM9EWWNH-9DBFSJjt4AmRbrcekG0r7ZR4c67GPzWNnwNhuhSHCbjTQXza2g1I3C4guQ6jB_7PiZ-97p33B70DgUlxPf86X3-eY4e-UY3N_XUQTAFJcVioIe4/s1600/1497379439446-image4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="871" data-original-width="1600" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3WyWQJFJjWI_ftw7fBf7fM9EWWNH-9DBFSJjt4AmRbrcekG0r7ZR4c67GPzWNnwNhuhSHCbjTQXza2g1I3C4guQ6jB_7PiZ-97p33B70DgUlxPf86X3-eY4e-UY3N_XUQTAFJcVioIe4/s320/1497379439446-image4.png" width="320" /></a></div>
<br />
<br />
So, GPU mining was immediately a huge leap forward, but it did not disrupt the market too much because GPUs are anyways consumer products. Sure buying 8 1080 Ti is quite an investment, but it is still feasible and anyways you could start with one and then expand (don't do it, not for Bitcoins at least, it would not pay off, keep reading).<br />
<br />
But GPUs are not the only computing hardware that deals well with parallel computing, FPGAs (Field Programmable Gate Arrays) are extremely interesting devices that allow the designer to create computing logic (including simple CPU cores) designed for a specific task.<br />
<br />
Now, GPUs were not designed to mine currencies, they were repurposed for that, while FPGAs are a sort of blank canvas that you can arrange pretty much the way you like (I played with them, you can see<a href="https://fortytwoandnow.blogspot.ch/2014/09/fpga-vga-interface-1.html" target="_blank"> how I created, ironically, a VGA interface</a>).<br />
<br />
The problem with FPGAs is that they tend to steeply increase in price when you need many logic cells (to accomodate many computing units) and performance.<br />
<br />
However FPGAs were invented to allow prototyping of solutions, whatever you can do with them it can be transferred to ASICs.<br />
ASICs are Application Specific Integrated Circuit and they are designed to perform a single task, they are not as versatile as CPUs.<br />
While you can purpose an FPGA (technicaly you synthesize a circuit) to do a task and then you can erase it and repurpose for something else, an ASIC is the implementation of one single circuit.<br />
<br />
ASICs are not a good solution unless you want to run a mass production, typically they will have a very high production setup cost and a low cost per item afterwards.<br />
<br />
When mining and Bitcoin became mainstream, the market was big enough to justify mass productions and that's when ASIC miners changed everything.<br />
<br />
Since they are designed for that specific role only, they are "cheap" and power efficient (that's why you should not mine bitcoins with your GPU), allowing massive parallel computing.<br />
<br />
Technically this changed the market because these are not typically consumer products, while you probably have at least one GPU in your house, chances are that you don't have an ASIC miner <i>(but you can buy one if you like, even tho it's profitability is going to drop quite quickly. Usually only the latest model is profitable, get ready to change them often)</i>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8Hr5FC2rzoeZqK9YJdyiRFK1O1HBH1rJXBzUPR7r-55mhGnsjOk6X7wZTcILMIZYyKJsJxonZYL6XQs9pUUri82kgA9GZdptbDGFdBGRj_k1nE9s1Esjq-lYeKGzfbVS2rxLm70SEBJo/s1600/T9.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="796" data-original-width="1078" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8Hr5FC2rzoeZqK9YJdyiRFK1O1HBH1rJXBzUPR7r-55mhGnsjOk6X7wZTcILMIZYyKJsJxonZYL6XQs9pUUri82kgA9GZdptbDGFdBGRj_k1nE9s1Esjq-lYeKGzfbVS2rxLm70SEBJo/s320/T9.jpg" width="320" /></a></div>
<br />
You can actually buy one, but again, unless your electricity is really cheap, you may waste money.<br />
<br />
This means that specialized companies were created, ususally they have access to cheap electricity (i.e. with Solar or geothermal) and always keep updated with the latest asic miner model.<br />
<br />
The reward of the mining process is linked to the average time effort of mining a coin, so those companies managed to blow out of the water all the home miners.<br />
<br />
At this point the cryptocurrencies, that were designed to be controlled by an extremely wide segment of the population, started to look like common valuable resources : controlled by big investors.<br />
<br />
To (try to) avoid that new currencies and markets were created such as <a href="https://www.ethereum.org/" target="_blank">Ethereum</a> or <a href="https://getmonero.org/" target="_blank">Monero</a>.<br />
<br />
They have many different peculiarities, but from the mining point of view, they tried to make the calcualtion less effective on ASICs.<br />
<br />
How to achieve that?<br />
We saw that ASICs are great for simple multi-threaded calculations (they run in parallel), so the approach was to make it more efficient for single threaded architectures.<br />
<br />
One path was to increase the complexity of the hashing algoritm or at least to make it less efficient by design.<br />
This favors cores with a high frequency (such as CPUs), but still running many computation simultaneously would be more efficient.<br />
So the trick was to artificially creaste a slow hashing algorithm that would need to use a lot of memory.<br />
Monero implemented the CyptoNight algorithm (for those who like technical documentation, check <a href="https://cryptonote.org/cns/cns008.txt" target="_blank">here</a>) which requires about 2MB of temnporary buffer (the "scratchpad") to compute tha hash.<br />
<br />
Why this is usually not a good fit for parallel comoputing?<br />
For every instance of the process you are running, you need to allocate a separate buffer so, if you have a 10.000 cores machine, you need enough memory to allocate 10.000 buffers.<br />
Memory is still relatively expensive and typically ASICs cannot have all that RAM available per core if we want them to have an acceptable price.<br />
<br />
A PC normally has a lot of RAM because we use it for many different tasks, plus, PC RAM modules are widely used so this brings their average cost pretty low.<br />
<br />
This worked when a top of the line VGA had 2GB of memory, it was still quite good to mine, but not much better than a CPU.<br />
<br />
Just to give you a feeling, this is a benchmark I just ran on my PC mining Monero (XMR):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh9kebus7RX-bdgqT_oR1gtwYYhwImdw8t8vZIz8xSaGoiRkh1nFtVTqdIGCFKRKBvm1qBZj_mJn_3nvzKSelM37TZ4uHPGMsZkxcpQmUC-UOzhEJkGv4tzJN7QnM-hkjbomUrKQoQGRo/s1600/hashing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="118" data-original-width="600" height="77" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh9kebus7RX-bdgqT_oR1gtwYYhwImdw8t8vZIz8xSaGoiRkh1nFtVTqdIGCFKRKBvm1qBZj_mJn_3nvzKSelM37TZ4uHPGMsZkxcpQmUC-UOzhEJkGv4tzJN7QnM-hkjbomUrKQoQGRo/s400/hashing.png" width="400" /></a></div>
<br />
<br />
<i>(my GPU is an old trusty Radeon HD 7870 with 2GB and my CPU is a Intel Core i5 4670K , both quite outdated now. The CPU is mining with 3 cores at about 1/3 of my GPU)</i><br />
<br />
Now the 1080 Ti sports 11GB or ram, that makes it pretty good with memory intensive hashing.<br />
<br />
In my example, I would be currently mining about 400 Hashes / second of Monero which would yeald to a wopping 1.21$ / day of reward (you can chek it <a href="https://www.cryptocompare.com/mining/calculator/xmr?HashingPower=400&HashingUnit=H%2Fs&PowerConsumption=0&CostPerkWh=0" target="_blank">here</a>, varies a lot with exchange rates, it's pretty high now) which is probably less than the cost of the power consumption of my PC.<br />
<br />
Many mining companies currently have mining rigs based on GPUs alongiside with their ASIC miners, so they can mine these currencies too.<br />
<br />
Still GPUs are a consumer product so they don't have a huge advantage versus home miners as their hash / watt rate is comparable.<br />
<br />
Is it going to last?<br />
Probably not, in fact the cost of the memory is merely a matter of scale : if those currencies become so attractive to justify bigger investments, then scale production of dedicated hardware with enough memory will become financially viable.<br />
<br />
However this memory inefficient algorithm is still a good solution : currencies are usually profitable to mine when they start (profit is balanced by the risk that the currency itself will not be successfull and eventually will fade to oblivion), then they usually pay less over time, when they are established.<br />
The Bitcoin millionaires are those that had the coins early on, they gambled, they won, fair enough.<br />
So, if this beginning fase does not favor big companies, but spreads the mining rewards over a wider population, to my book, it's already a success.<br />
<br />
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com1tag:blogger.com,1999:blog-3747970306027691432.post-25125251073727855892017-12-03T15:13:00.000+01:002017-12-03T21:16:28.225+01:00Making sense of cryptocurrenciesThere is a lot of talk about bitcoins and the other crypto-currencies lately.<br />
"BlockChain" is a hype word and a sort of "myth" has been created around it, but in reality it is something quite simple and not really new as a concept.<br />
<br />
What is "new" (ahem... since a few years at least) is the fact that it is applied to a digital currency.<br />
<br />
I have been discussing this topic with few friends lately, so I thought some basic explanations might be generally useful since my impression is that most of the people thinks it is more complex than it actually is.<br />
<br />
If you don't quite understand how it works, I will try to explain it in this post, in a way that should not assume any particular technical skills.<br />
<br />
<b>Ingredients</b> : Blocks , hashcodes, wallets, distributed ledger<br />
<br />
Let's start from the last one, the<b> Distributed Ledger</b>.<br />
<br />
First off: it is a public ledger, imagine a spreadsheet with lines that record money movements from and to all the people (who use the cryptocurrency) in the world.<br />
<br />
John gives Martha 0.001 coins , that's your first ledger entry, everybody can see it.<br />
<br />
Now, how do we identify John and Martha? We give them an unique address, in the form of a long string such as <b>xxo6YxxL19qs5JxxxxMaea4xxxxL55vmNr</b><br />
That's my bitcoin receiving address (<i>to which I replaced a few letters with "x" so that you don't send me money by mistake :)</i> ).<br />
<br />
The ledger is public, but the entities mentioned in it are only identified by an address (which somehow prevents governments to knock on your door asking taxes on them).<br />
<br />
Why can't you simply get my bitcoins at my address? Well, turns out that my balance goes into a wallet, to open it you must be able to decrypt it with a proper key that I (and everybody else having a digital wallet) created.<br />
Provided that balances can be attributed to a given address, only the person being able to open the associated wallet will be able to claim them.<br />
There is a bit more to it, but let's leave it like that.<br />
<br />
Since the ledger is distributed, many million copies exist, so the likelyhood of them being lost is pretty low.<br />
Also this prevents people to spend coins they don't have as transactions are verified (if you are sending x coins, your running balance should be at least x) before inserting a block in the ledger.<br />
<br />
<b>Blocks</b> :<br />
instead of adding single rows to the ledger, like you would do in a spreadsheet, transactions are grouped in blocks, imagine a list of 20 spreadsheet rows.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhty0F4eUi2aZ8DStWTDL8BXEh7IQ1Qm1omY21oXlhhKDKEO0jWsf9EP0J5I2oHkb2t9ha4KsL5sPBNQ0VNAkK-chkscjJLbqAbHM_OplB0l1fpk6DtjDIETYq2iXoqXgm8ftYwizs1HC8/s1600/bchain.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="311" data-original-width="1107" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhty0F4eUi2aZ8DStWTDL8BXEh7IQ1Qm1omY21oXlhhKDKEO0jWsf9EP0J5I2oHkb2t9ha4KsL5sPBNQ0VNAkK-chkscjJLbqAbHM_OplB0l1fpk6DtjDIETYq2iXoqXgm8ftYwizs1HC8/s640/bchain.png" width="640" /></a></div>
<br />
<br />
The tricky part here is that the blocks are "chained" into the ledger, meaning to insert block n you need to know block n-1.<br />
This is where hashcodes enter in the scene :<br />
A hash is an algorithm that takes a bunch of data and outputs an identificative code for it.<br />
This is a destructive transformation, meaning that you take the input data and you get a deterministic result (if you apply the same algorithm n times to the same input you always get the same result), BUT knowing the result does not allow you to compute the original data.<br />
There are plenty of hashing algorithms, Bitcoin uses SHA-256 which outputs a 256 bit value (a 32 byte binary code).<br />
You may have a block of 1Megabyte or 1Kilobyte worth of data, but their hash will always be 32 bytes.<br />
<br />
Blocks, before the list of transactions, contain the hashcode of the previous block, this means that if any block is changed in the ledger, all the subsequent blocks will have a wrong hashcode, this prevents tampering with past transactions (and the resulting balances).<br />
<i><br /></i>
<i>If you have hard time to visualize this process, just think about prime numbers : they are actually a chain since you cannot compute a nth number unless you know the n-1 ones.</i><br />
<br />
At this point everything would be easy: get a new block of transactions, calculate the hashcode of the last block, add the value to the current block, append. Done.<br />
<br />
Actually not quite, this is where mining becomes part of the game.<br />
Calculating a SHA-256 hashcode is something that modern computers manage quite easily, but then there would be no effort to run the operation, therefore it would be impossible to attribute a reward to it.<br />
<br />
To generate artificially an effort, a condition is added : the resulting hashcode must start with a given number of 0 bits.<br />
This number varies and sets the "difficulty" of the mining for a particular currency. As computing power increases, so does the difficulty to avoid uncontrolled inflaction of rewarded values.<br />
<br />
But we said that a given block of data can produce a single hash with a given algorithm, how can we ask it to start with a number of leading zeros?<br />
We can't, this is why <u>we change the data</u> of the block, but we cannot change the transactions, so there is a field called "nonce" in the blocks, consisting of four bytes (32 bits) for us to change.<br />
<br />
Altering the nonce field and computing the sha-256 hashcode until we get a "golden" hash (with the required leading zeros) is the mining process, it usually require many iterations.<br />
Since it is impossible to start from a hash and get the input data, we have to run a loop with trial and error, until we find the desired hash.<br />
<br />
Once the golden hash has been found, the "proof of work" is simply the nonce used to alter the data block. Everybody can verify the resulting hash conforms to the difficulty requirements.<br />
<br />
When you hear about services, hardware etc that can generate a given number of hashes / second (aka hashrate : could be Mega hashes /s, Giga hashes /s, Tera hashes /s ) that's a measure of how many attemps per second that particular hardware or service is able to deliver.<br />
<br />
I will not enter into technological or financial considerations here (maybe in a future post, who knows?), but I hope you understand the basic concept behind blockchain is quite simple... and probably that's the beauty of it.<br />
<br />
P.S. : No, in general it is not worth mining currencies on your computer as an individual or as a part of a pool. Money can be made, but usually at a larger scale.<br />
There are better options to gain money (<i>like doing some actual work and getting paid for it :) </i>). Cloud mining can be an option too (major players are <a href="https://www.genesis-mining.com/" target="_blank">Genesis Mining</a> and <a href="https://hashflare.io/r/BD7A2E" target="_blank">HashFlare</a>) ,be aware that in general these are high risk investments.<br />
I have a small investment with <a href="https://hashflare.io/r/BD7A2E" target="_blank">HashFlare</a>, not really planning to make any money out of it, but that gives me the opportunity to experiment and better understand how the whole cryptocurrency marketplace works.<br />
<br />
<br />
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-32701881318045465152017-05-27T22:38:00.003+02:002017-05-27T22:38:57.854+02:00STM32 Graphic capabilitiesI had a great opportunity yesterday, the kind of opportunities I usually try not to waste: I was offered to learn something!<br />
<u>Never</u> pass an opportunity like that!<br />
<br />
But that was just the beginning of my luck.<br />
What if I tell you the topic was incredibly cool, that the instructor definitely knew his stuff, the same stuff I have been struggling around for a while, before getting invited at this free 1 day training?<br />
<br />
Does it get any better? Actually it does, the whole thing came with free pizza (and a STM32F746 discovery board too!).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.st.com/content/ccc/fragment/product_related/rpn_information/board_photo/group0/ea/c4/6d/73/c3/f5/46/e2/stm32f746g-disco/files/stm32f746g-disco.jpg/_jcr_content/translations/en.stm32f746g-disco.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.st.com/content/ccc/fragment/product_related/rpn_information/board_photo/group0/ea/c4/6d/73/c3/f5/46/e2/stm32f746g-disco/files/stm32f746g-disco.jpg/_jcr_content/translations/en.stm32f746g-disco.jpg" data-original-height="571" data-original-width="800" height="228" width="320" /></a></div>
<br />
<div style="text-align: center;">
<i>(Sorry, don't have an image of the pizza)</i></div>
<div style="text-align: center;">
<br /></div>
Jokes aside, <u>thanks</u> ST Microelectronics for this opportunity.<br />
<br />
As usual, one of my preferred ways of writing down notes about something I learnt or I am learning is to write a blog post, it definitely helps me in the process of digesting the information and, from some feedback I received, it turns sometimes helpful to others too.<br />
<br />
Ok, enough blah blah, down to business.<br />
Graphics, oh yeah!<br />
<br />
Let's start from the basics.<br />
<br />
We live in a world where even toilets might have some GUI (not joking, see yourself..)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8JYwBTEX3wsFbYmtMaE60QrixOBXVI1mGD3HpKWHsuyPbxYiO8fsrWFHO8llk_BcXJbL3DmpgaxUSyYHilVtGANMQHxnCYKI7XgxkS3vgLSsJif92qa04FCmc867Qo26OQzoKY-0ldI4/s1600/Wireless_toilet_control_panel_w._open_lid.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="750" data-original-width="800" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8JYwBTEX3wsFbYmtMaE60QrixOBXVI1mGD3HpKWHsuyPbxYiO8fsrWFHO8llk_BcXJbL3DmpgaxUSyYHilVtGANMQHxnCYKI7XgxkS3vgLSsJif92qa04FCmc867Qo26OQzoKY-0ldI4/s320/Wireless_toilet_control_panel_w._open_lid.jpg" width="320" /></a></div>
<br />
..so, adding graphics capabilities to MCUs seems just natural.<br />
You can find in the web several projects even with Arduino unos and some SPI screen, some are pretty damn cool too.<br />
However if you want something a bit more performant, you need horse power.<br />
Cortex cores (from M3 upwards) start to get you in the ballpark, but for complex applications, you may need to scale up to M4s and M7s.<br />
A 32 bit risc processor running at 216MHz such as the <a href="http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32f7-series.html?querycriteria=productId=SS1858" target="_blank">STM32F746</a> has the needed computational power to support a modern interactive GUI.<br />
<br />
Turns out the horsepower is not all, there is more because we <u>need</u> more.<br />
<br />
Ideally you want your gui to<br />
1) run on a screen with decent definition (the bigger the screen, the higher the definition in order to mantain an acceptable DPI resolution)<br />
2) Have a high refresh rate (60Hz would do)<br />
3) Have decent color depth, such as 16 or 24 bits<br />
4) Avoid to drain your CPU as it usually needs to do other suff in the meanwhile, like reacting to your inputs.<br />
<br />
If you put all that together you discover that you need a fast processor, with quite a bit of ram and maybe some easy way to expand it with fast external SDRAM, you need maybe some fast storage for your images, and ideally something that deals with the complexity of the screen interface for you.<br />
<br />
The thing is, it is not enough to solve ONE problem, you need to solve them all... and that's the kind of thing where MCUs excell, they provide you with a set of integrated peripherals designed specifically to tackle all the needs for an application.<br />
I believe the STM32F7 is one remarkable example of that (Note : I am not sponsored by ST, although, techncially... they gave me a free pizza so... I might be biased :) ).<br />
<br />
To explain why I believe the F4 and F7 families have very good features to support a gui, let's analyze what are the things that are needed.<br />
<br />
If you are interested in getting the details, ST has great documents such as the <a href="http://www.st.com/content/ccc/resource/technical/document/application_note/group0/25/ca/f9/b4/ae/fc/4e/1e/DM00287603/files/DM00287603.pdf/jcr:content/translations/en.DM00287603.pdf" target="_blank">Application Note AN4861</a>, which I strongly encourage you to check.<br />
<br />
When you interface a screen you can chose different devices, but there are mainly two (more actually, read the AN4861 for that) kind of screens :<br />
- Those that have memory and timing controller onboard<br />
- Those that don't<br />
<br />
The TFT screens you see around connected with arduinos or even Cortex M3s in projects are usually of the first kind.<br />
You can find them on ebay for few bucks so, why would you even consider the second kind?<br />
Typically, if you need a higher resolution than 320x240 with a decent color depth and refresh rate, you need to manage yourself the controller and that adds quite a bit of complexity.<br />
You need to manage the timing for the sync signals (see my posts <a href="https://fortytwoandnow.blogspot.com/2014/09/fpga-vga-interface-1.html" target="_blank">here</a> and <a href="https://fortytwoandnow.blogspot.ch/2014/09/fpga-vga-interface-2.html" target="_blank">here</a> if you understand a bit of Verilog and FPGAs) and a 24 bit parallel interface for the colors, but the worse part is that the two must be precisely synchronized.<br />
Say that you are refreshing a VGA screen at 60Hz, that means that at any specific instant you have to send the exact RGB values to correctly draw the current pixel, over and over.<br />
If you CPU is dealing with that, probably it is not going to be able to do much more.<br />
A cortex M7 @216Mhz might be able to do that, but actually it does not have to because you want to save your CPU clocks for your application, besides the GUI.<br />
<br />
ST added to some F4 F7 and L4 devices a peripheral called <b>L</b>CD - <b>T</b>FT <b>D</b>isplay <b>C</b>ontroller (LTDC).<br />
It can interface with several kind of displays (note : depending on the device itself, some recent interface technologies might or might not be supported), it is integrated in the MCU and can access the MCUs DMA channels.<br />
Basically you define a buffer in memory (internal or external memory, works just the same) and your code populates this buffer with your graphics, the LTDC reads it authonomously and provides the needed signals for the display, no CPU needed once you started it.<br />
And that's your RAM you are dealing with, the fastest thing you can read and write to from your MCU, no match for a SPI interface.<br />
<br />
During a hands-on lab in the training I was debugging the code, the execution was halted at a breakpoint so the CPU was actually waiting, not doing anything. Still the internal LTDC was refreshing the screen, completely authonomously, just like if the screen had its own controller and ram buffer onboard (and it did not, the screen is a RK043FN48H-CT672B, it has an RGB parallel interface, no controller).<br />
<br />
So, the LTDC plays an important role in enabling graphics capabilities and it does it allowing quite a bit of flexibility.<br />
<br />
A second key component for the solution is RAM : GUIs in high resolution are memory hungry and this requires two things :<br />
1) A decent amount of internal memory and / or an easy way to integrate inexpensive and powerful external memories<br />
2) An efficient high bandwidth DMA<br />
<br />
The F7 shines there, I suggest you check the schematics for the F7Discovery board, it is surprisingly (to me) quite readable and extremely informative.<br />
The beauty is that the LTDC can tap with no issues in that DMA, in fact it is a master device in the AHB<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIfANZZ1FH3ooaGfyd6pjz1YP6EGSQ6A-Blir5ZUlLJnSzw_f79xGO_JxJqyD8wZTB7fUfOORNvoSlq2jQzmWz8itDUSu4LF0gQkOfcZVqC5BblYVi-UEyLMfBPS2qkkswfTUwHGNrB6U/s1600/ahb.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="735" data-original-width="927" height="506" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIfANZZ1FH3ooaGfyd6pjz1YP6EGSQ6A-Blir5ZUlLJnSzw_f79xGO_JxJqyD8wZTB7fUfOORNvoSlq2jQzmWz8itDUSu4LF0gQkOfcZVqC5BblYVi-UEyLMfBPS2qkkswfTUwHGNrB6U/s640/ahb.png" width="640" /></a></div>
<div style="text-align: center;">
<i> from the AN4861 @ST Microelectronics</i></div>
<br />
If you want to learn more about the F7 architecture, ST has a nice MOOC training about it, you can search it on their website.<br />
<br />
The potential draw-back of this kind of solution is that you have a high pin count to connect to the display (24 for the RGB, 3 for the sync signals, something to control the backlight, an I2c eventually for the touch panel...) wich calls for some "interesting" PCB layout and also you should expect to deal with high pin count devices, typically BGAs... maybe not all of you -nor me anyways- will be able to solder those in your kitchen.<br />
Some new technologies such as <a href="https://en.wikipedia.org/wiki/Display_Serial_Interface" target="_blank">MIPI-DSI</a> , supported in some STM32 devices, solve that problem, I will not enter in details here.<br />
<br />
So, now we can update the screen and we have a fast access to the frame buffer, being internal or external, that's a lot already, but it's not all.<br />
<br />
<b>Chrom-ART, aka DMA2D.</b><br />
This is another important component for graphics of the STM32 architecture, it actually helps in populating your frame buffer.<br />
Imagine your gui has a background image and some buttons with icons.<br />
What you do is you get the background image maybe from a QSPI ram, copy it on the frame buffer, then you draw the buttons, back in the QSPI to fetch tthe icons, and finally copy them on the framebuffer as well.<br />
It works, but requires wuite some effort to the CPU to handle all those memory transfers... unless you have a DMA2D which gladly takes care of that for you.<br />
It's pretty cool, read more about it in the <a href="http://www.st.com/content/ccc/resource/technical/document/application_note/group0/17/82/73/f8/b8/8a/47/c7/DM00338361/files/DM00338361.pdf/jcr:content/translations/en.DM00338361.pdf" target="_blank">AN4943 </a>application note document :)<br />
<br />
Finally, all this is indeed amazing, but how does it come all together when you are writing an application?<br />
The keyword here is : Software libraries.<br />
By any means, you can fire up you STM32CubeMX, activate LTDC, DMA2D, QSPI and whatever you need, then use HAL drivers to do your magic.<br />
I tried and failed, maybe now I might have a better chance at it as back then I had very little understanding about what I just wrote in this post.<br />
Is there another way?<br />
Yes, as I said, software libraris.<br />We played with 3 of them during the training, all 3 looked pretty good to me even if you may want to use them for sligthly different purposes.<br />
We tried <a href="http://www.embedded-wizard.de/" target="_blank">Embedded Wizard</a> , <a href="http://touchgfx.com/" target="_blank">touchGFX</a> and <a href="https://www.segger.com/emwin-samples.html" target="_blank">STemWin (Segger)</a>.<br />
Those libraris smoothly and seamlessly integrate with the STM32 hardware, you don't even need to care about LTDC, DMA2D etc... they take care for you, and they do way more.<br />
They have a PC based design where you build graphically your gui, including interaction with the touch screen, and then c code is generated for your device.<br />
They work in slightly different ways, EW and tGFX have a well integrated environment, they deal with most of the tasks for you, while emWin requires a bit more coding.<br />
I personally prefer the emWin approach because I feel it gives me better control over the code, but you pay that with more effort in most cases.<br />
Also the PC tools are a bit less polished, but again, that's not a main concern for me.<br />
One good thing about STemWin is that it comes for free with STM32 devices since ST made an agreement with Segger, customized/optimized the code for its devices and provided licenses for free to its customers.<br />
If you have a medium to big sized project, you probably are not going to decide based on library license costs anyways.<br />
My impression (but I still need to play more with those libraries) is that EW and tGFX may provide a faster time to market option and ensure good performances.<br />
With STemWin I think you can achieve good performances, but it is up to you to optimize the process.<br />
<br />
To wrap it up, ST seems to be quite committed in supporting graphics capabilities by :<br />
- Providing fast MCUs (the STM32H7 will run at 400MHz!)<br />
- Providing peripherals to remove load from the MCU and to ease the integration with memory and displays<br />
- Working with partners to boost the software ecosystem<br />
- Supporting customers with good documentation, examples and training<br />
- PIZZA!<br />
<br />
I may write more on this topic once I played a bit more with the libraries, maybe with some code examples.<br />
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com1tag:blogger.com,1999:blog-3747970306027691432.post-42023484711190867152017-02-10T16:22:00.000+01:002017-02-12T12:53:54.955+01:00STM32 Programming Ecosystem<div style="line-height: 100%; margin-bottom: 0in;">
Not long ago I
started playing with STM32CubeMX and Eclipse to do some experiments
with the STM32 ARM Cortex M3 processors.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Setting up the
toolchain, the IDE etc was a bit complex, so I decided to create a
youtube video about it, thinking it might be useful for others going
through the same thing.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/XRzQ_L_eSSk/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/XRzQ_L_eSSk?feature=player_embedded" width="320"></iframe></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
The reason why I did
things that way was that with my Eclipse/ARM setup I was planning to
use also other (non ST) devices, so it made sense not to use the ST
specific version of the tools, which was also bound to the Mars
eclipse version while I normally use Neon now.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
I was wrong.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
I mean yes, the
intent made sense, but honestly all the additional hassle to avoid
installing a new Eclipse instance was not worth it.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
A couple of days ago I was
lucky enough to participate to an extremely interesting Workshop at
the ST Headquarters in Geneva (Switzerland).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
They explained how
to setup the tools,provided a few tips on how to best use them and provided
extremely valuable information.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
The workshop was engaging, well paced and indeed informative, kudos to ST
for it ad thanks again for the invitation!</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
The workshop will be
held in various cities in the next days (at the time I am writing), I
strongly encourage you to participate if you are interested (it is free).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
This is the link for
Europe, you might need to search around their website if you are
interested in other regions, there might be something available, not
sure</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
http://www.st.com/content/st_com/en/about/events/events.html/stm32-ecosystem-emea.html</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Now I need to
capture in a new video the “standard/correct way” of doing
things, I do it mainly because it is a sort of collection of minutes
for myself, but then again, others might benefit from it.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
ST uses a
proprietary very low cost interface to allow you program and debug
its chips, this interface is called<a href="http://www.st.com/content/st_com/en/products/embedded-software/development-tool-software/stsw-link009.html" target="_blank"> ST-Link</a>, which is basically an
alternative to a standard JTAG (I normally use Jlink from Segger).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
All the official
boards include this interface and this allows you to plug in an usb
cable and do all the programming/debugging thanks to a Windows
driver.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
No need for
additional hardware.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
However, should you
have a non official ST board -that has no usb debugging- with one of
their STM32 chips on it, chances are that it exposes the pins needed
for the ST-Link interface, which you can grab for few bucks (less
that 3$ shipped on ebay).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
While a full blown
JTAG device such as the Jlink might provide some more
functionality/speed I have to admit that the cheap ST-Link will
probably get the job done for everybody.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9kf_pKbcaDdPIA801Wz4alPbguQwZok_dDXwx4G44cTCMFhafZl5ZBjUpq_qaQ6me8Z3Vd4HFlPbRr4CVhiwXH8kj5lJRVKCCUlJ3oVlC2DnTJqZxvWfInybwvn9OhdFgIUbx9K-ElCI/s1600/stlinku.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="199" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9kf_pKbcaDdPIA801Wz4alPbguQwZok_dDXwx4G44cTCMFhafZl5ZBjUpq_qaQ6me8Z3Vd4HFlPbRr4CVhiwXH8kj5lJRVKCCUlJ3oVlC2DnTJqZxvWfInybwvn9OhdFgIUbx9K-ElCI/s320/stlinku.png" width="320" /></a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
There is an
(optional) utility you can use to upload the binary file on the STM32
flash, using ST-Link, this is called<a href="http://www.st.com/content/st_com/en/products/embedded-software/development-tool-software/stsw-link004.html" target="_blank"> ST-Link utility</a>.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
I am saying
“optional” because usually your programming IDE will be able to
do that too, interfacing directly with the ST-Link driver.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
When it comes to the
IDE,while there are many different valid options, ST proposes a free
solution based on Eclipse (Mars 2 at the moment).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
If you followed my
previous video, you saw that you need to install three main
components with you IDE :</div>
<div style="line-height: 100%; margin-bottom: 0in;">
1) The IDE / Code
Editor itself</div>
<div style="line-height: 100%; margin-bottom: 0in;">
2) The ARM toolchain
(compiler, builder, linker, make…)</div>
<div style="line-height: 100%; margin-bottom: 0in;">
3) The Debugger
interface</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
The good news part
is that if you choose to go with the ST standard IDE (System
Workbench – SW4) this is all taken care of, since ST packaged an eclipse environment that contains all the needed components.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
I strongly recommend
this approach, makes things WAY easier.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
System Workbench
comes with the <b>Ac6 STM32 MCU GCC toolchain</b>.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzgGT6gn20WxyfQneMk9-EqdG1yfnBEcpJZpFolQGI8P-r4JG9iUxmAmbQmShujHkgsK7isKMSB9T4voYZO49zis1M277aywmp1qnR3pzqEML9Qii838E1Ib35E065Cq-mlH4wb7-tVpE/s1600/ac6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzgGT6gn20WxyfQneMk9-EqdG1yfnBEcpJZpFolQGI8P-r4JG9iUxmAmbQmShujHkgsK7isKMSB9T4voYZO49zis1M277aywmp1qnR3pzqEML9Qii838E1Ib35E065Cq-mlH4wb7-tVpE/s320/ac6.png" width="320" /></a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
I like Eclipse, I
admit it might be a bit “scary” at the beginning, but it is well
worth spending a little bit of time to learn it since it can be used
in so many different solutions (Coding any language / platform, ETL,
Data Mining…).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
With System
Workbench (SW4) you can create your projects, but creating a Cortex
M Project requires a few steps which include adding the relevant
libraries / header files for your specific devices (CMSIS and
additional stuff).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
Like most IDEs, SW4
takes care of that, it will simply ask you which device or board you
are targeting.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
But it does more
than that, it will automatically allow you to chose which additional
libraries to include or even which middleware (such as freertos).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
… but you will
probably not even use those features.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
Why? Don’t get me
wrong, they provide tremendous help, but the reason why you may not
want to use them is that you can do the same in an even better and
easier way!
</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Imagine you were
able to add all the libraries, middlewares, set up the correct stack
and heap map etc, what would be your next step in the project?</div>
<div style="line-height: 100%; margin-bottom: 0in;">
These MCUs have an
incredible number of peripherals, you will probably use a few of
those in your project, so the first step is usually to set up the
clock(s) and then enable and configure the multiplexer for the
different pins and the peripherals you need to use.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
While it obviously
depends on the complexity of your project, this usually requires
quite a bit of work, what if you could skip most of that?</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin2vjg_kOJRH25ZDfSJrmvv3Zt9RvsDcIR-a_s4abe0i2Jc0B8atcDXMcRr4ucsOhPrShTj_tmtEFxrszWjJdsVxC5J1feisp86I3qVRvR1dG7GaI2O1k7MF28clqvqGnASXcC1J9M8IQ/s1600/cube.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="267" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin2vjg_kOJRH25ZDfSJrmvv3Zt9RvsDcIR-a_s4abe0i2Jc0B8atcDXMcRr4ucsOhPrShTj_tmtEFxrszWjJdsVxC5J1feisp86I3qVRvR1dG7GaI2O1k7MF28clqvqGnASXcC1J9M8IQ/s320/cube.png" width="320" /></a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Actually you can,
let me introduce you to STM32CubeMX.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
You are not obliged
to use it, but I cannot imagine a reason why you would not.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
For starters:It’s
free and it nicely exchanges information with your IDE (SW4 is
obviously supported, but so are Kyle and IAR).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
What the cube does,
is to help you set up your project by doing pretty much the same
thing I said you would skip in the project creation in the IDE, PLUS
it guides you in setting up your peripherals and the clocks.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
Once you are
finished, it generates a project dor your IDE with all the
configuration set correctly for you and with a code skeleton that
configures initializes the peripherals you selected.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
Usually you decide
upfront which peripherals you need to use and how they should be used
and add your code later, but CubeMX allows you to change your mind.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
In fact when it
regenerates the skeleton code, it uses some specific comment tags to
preserve code that you eventually added.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
You need to be
careful then, on where you write your code, in the skeleton files
Cube will add lines like these</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<span style="color: #626262;"><span style="font-family: "consolas" , serif;"><span style="font-size: 10pt;">/*
USER CODE BEGIN 0 */</span></span></span></div>
<div align="left" style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<span style="color: #626262;"><span style="font-family: "consolas" , serif;"><span style="font-size: 10pt;">/*
USER CODE END 0 */</span></span></span></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
That means that if
you need to add your code, it should be placed between those two
lines, there are many different sections, in different places, where
you can place your code.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
As long as you
respect this rule, you can go back to CubeMX, change whatever you
need to change there and regenerate the code, the code you added will
be kept in the new skeleton.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
That DID NOT work in
my previous setup (Users Eclipse with ARM GNU Toolchain manually
setup, instead of using SW4), but maybe it was just me messing up
things.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
It definitely works
smoothly using SW4.
</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifPlJsxkQiZwscfMF-7GFyLnC_AIWnPSVXDBHxe2fKO2KGOH2E5dP7PYExiX-5k-sdDTGzPgJBrYjQ-GYcyTBvqX0Qi36Gyw4iflgzREwIjedH_zg4Assk63nTN6nRYAzBOXnJgPRkoYE/s1600/studio.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="110" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifPlJsxkQiZwscfMF-7GFyLnC_AIWnPSVXDBHxe2fKO2KGOH2E5dP7PYExiX-5k-sdDTGzPgJBrYjQ-GYcyTBvqX0Qi36Gyw4iflgzREwIjedH_zg4Assk63nTN6nRYAzBOXnJgPRkoYE/s320/studio.png" width="320" /></a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
The final component
is <a href="http://www.st.com/en/development-tools/stm-studio-stm32.html" target="_blank">STMStudio</a>.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
You can use it to
debug your applcation, this is nto the only option obviosuly, since
the IDE already includes a pretty good debugger, but STMStudio gives
you a nice and simple way of monitoring variables (with graphical
output eventually, sometimes it is useful).</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Indeed there are
many ways of customizing this ecosystem, but I found that,
particularly if you are not an expert, it really helps in sticking to
the standards: SW4, STM32CubeMx, ST-link and STMStudio seem to work
very well together.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Here the links to
download them :</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<b>ST-Link Drivers</b> -
<a href="http://www.st.com/content/st_com/en/products/embedded-software/development-tool-software/stsw-link009.html">http://www.st.com/content/st_com/en/products/embedded-software/development-tool-software/stsw-link009.html</a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<b>ST-Link Utility</b> -
<a href="http://www.st.com/content/st_com/en/products/embedded-software/development-tool-software/stsw-link004.html">http://www.st.com/content/st_com/en/products/embedded-software/development-tool-software/stsw-link004.html</a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<b>STM32CubeMX</b> -
<a href="http://www.st.com/en/development-tools/stm32cubemx.html">http://www.st.com/en/development-tools/stm32cubemx.html</a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<b>System Workbench</b> -
<a href="http://www.st.com/en/development-tools/sw4stm32.html">http://www.st.com/en/development-tools/sw4stm32.html</a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<b>STMStudio </b>-
<a href="http://www.st.com/en/development-tools/stm-studio-stm32.html">http://www.st.com/en/development-tools/stm-studio-stm32.html</a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Happy coding!</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<i>The new video is here</i><br />
<i><br /></i>
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/xoXkyImSao0/0.jpg" src="https://www.youtube.com/embed/xoXkyImSao0?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<i><br /></i></div>
<div style="line-height: 100%; margin-bottom: 0in;">
</div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com2tag:blogger.com,1999:blog-3747970306027691432.post-89011287434704578852015-08-14T10:43:00.001+02:002015-08-14T10:45:37.226+02:00TI RTOS - thread synchronizationI don't have much free time these days, but when I have a spare hour, I like to play with the TI RTOS, following the <a href="http://fortytwoandnow.blogspot.ch/2015/08/playing-with-ti-rtos.html" target="_blank">great online workshop I discussed in my previous post</a>.<br />
<br />
The BIOS (Kernel) of the OS allows you to create threads (functions) that run with different priorities and that respond to an hardware interrupt (Hwis) or a software generated "event" (Swis, Tasks) or simply run continuously whenever the OS is not busy with other stuff (Idle).<br />
<br />
All that is quite cool and also rather easy to implement, but soon you discover you may need to implement some sort of synchornization between your threads, eventually passing values from one thread to another.<br />
Say you have a Hwi that triggers whenever data is received on the UART, it sends the buffer to a Swi that reads it and interprets data (i.e. commands you are sending remotely, let's imagine it's ASCII based and at every \n you mark the end of a command).<br />
<br />
What happens is that once you receive a command, you want to react accordingly and this reaction may take a few CPU cycles, for instance to turn a stepping motor X steps in a given direction.<br />
Meanwhile your UART is still receiving other commands.<br />
<br />
You see it's easy to get in a difficult situation where buffers are overrun or changed while you are using them.<br />
<br />
The worst solution to exchange data across the different threads is to use global variables as buffers, these will easily get manipulated while you are using them.<br />
sure, there are a few ways to protect your system from this to happen, but most of those "solutions" are likely to introduce even worse problems.<br />
<br />
But hey, we have an OS, remember?<br />
The RTOS has built in capabilities to regulate the execution of the tasks.<br />
<br />
<b>Semaphores</b><br />
<br />
A Semaphore can be used to pause (pend) a task untill another task tells it (post) to run.<br />
<br />
It is somehow similar to an event, but it does not trigger a function (like an event would do), instead it tells it (whenever the bios scheduler decides to give back the Program Counter to it, based on priority settings) to keep running.<br />
<br />
<i>Example </i><br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">void myTask()</span></b><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> .. do some init stuff...</span><br />
<span style="font-family: Courier New, Courier, monospace;"> while (1) // run forever</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ... do some other stuff ...</span><br />
<span style="font-family: Courier New, Courier, monospace;"> <b>Semaphore_pend(myCoolSemaphore);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"> ... get the data and use it...</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
It is cool, indeed, but if we need to echange data, the Semaphore is not enough.<br />
<br />
So, there are features in the OS that allow one thread to send a buffer with a message.<br />
This message can be in a <b>Queue</b> or in a <b>Mailbox</b>.<br />
<br />
Queues and mailboxes are slightly different, the main difference is probably that messages in mailboxes are in fact copies of the data, meaning that the sender and the receiver do not share the same memory locations when accessing the data, while queues pass pointers.<br />
Another important difference is that mailboxes have built-in semaphores, while Queues don't, you need to provide a semaphore for synchronization purposes.<br />
<br />
The overall idea is that along with a synchronization signal you can send data, i.e. the buffer containing the command.<br />
However we can have several mails in a mailbox, making the system automaGically multi-buffered.<br />
<br />
So, going from a single buffer to a n-buffer solution if using queues and mailboxes is mainly a configuration task (you set up values in the GUI, no coding needed for this).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibVqyl6zpQ0vGk-ymgyTJ1NF3cXGFTEaJsw8XPOPeDsmPfhyphenhyphenAjAHCLBEYClhT9hAbqD5WKcRxELvNje1DTj_MZdkHetXMwqURbeh90nUr8m7NajF9Y5IybK_r9DTPBXXbeFZxo0zbiLqc/s1600/buffer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibVqyl6zpQ0vGk-ymgyTJ1NF3cXGFTEaJsw8XPOPeDsmPfhyphenhyphenAjAHCLBEYClhT9hAbqD5WKcRxELvNje1DTj_MZdkHetXMwqURbeh90nUr8m7NajF9Y5IybK_r9DTPBXXbeFZxo0zbiLqc/s400/buffer.png" width="391" /></a></div>
<br />
The picture (app.cfg edited in CCS 6.1.0) shows a double buffer implemented with a mailbox with 2 max messages.<br />
<br />
The example, taken from the TI RTOS Workshop (see previous post) lab 9 does the following:<br />
<br />
1) An Hardware timer generates an interrupt every 500ms<br />
2) An Hwi function associated to the timer int posts a semaphore<br />
<br />
<b>void Timer_ISR(void)</b><br />
{<br />
TimerIntClear(TIMER2_BASE, TIMER_TIMA_TIMEOUT);<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<b>Semaphore_post(mailbox_queue_Sem);</b><br />
}<br />
<br />
3) A mailbox management task waits (pends) for the semaphore and when it receiveds a green light, it posts to the mailbox.<br />
Notice that in this case the "data" is generated here (msg.val is toggled).<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">void mailbox_queue(void)</span></b><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> MsgObj msg;</span><span class="Apple-tab-span" style="font-family: 'Courier New', Courier, monospace; white-space: pre;"> </span><br />
<span style="font-family: Courier New, Courier, monospace;"> msg.val = 1;<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace;"> while(1)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> msg.val ^= 1;<span class="Apple-tab-span" style="white-space: pre;"> </span>// toggle msg.val (LED state)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> <b>Semaphore_pend(mailbox_queue_Sem, </b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> BIOS_WAIT_FOREVER);</b><span class="Apple-tab-span" style="white-space: pre;"><b> </b></span></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <b>Mailbox_post (LED_Mbx, &msg, </b></span><br />
<div>
<b><span style="font-family: Courier New, Courier, monospace;"> BIOS_WAIT_FOREVER); </span></b> <span style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
4) A task that actually reacts on the data (toggles a led) waits for the mailbox<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>void ledToggle(void)</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> MsgObj msg;<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace;"> while(1)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> <b>Mailbox_pend(LED_Mbx, &msg, </b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> BIOS_WAIT_FOREVER);<span class="Apple-tab-span" style="white-space: pre;"> </span></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> </b>if (msg.val)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> { // turn LED on</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> GPIOPinWrite(GPIO_PORTF_BASE,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 8) </span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> else</span><br />
<span style="font-family: Courier New, Courier, monospace;"> { // turn LED off</span><br />
<span style="font-family: Courier New, Courier, monospace;"> GPIOPinWrite(GPIO_PORTF_BASE, </span><br />
<span style="font-family: Courier New, Courier, monospace;"> GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
We can observe what happens thanks to the UIA (Unified Instrumentation Architecture) that allows to interface with the OS via the JTAG port and gather execution details.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmlAarkMnSUXE0ZKwuhLwJL7XUCbQi86hZoFiEZN2sZKWg-w8oprZHmYzh6nDqQOdEcZ_CMrTeITgrx5WqtIg-U_Y_m8ryq5kALJ69H8nWKB8BJfLyaXHjUh4s_-f8a1ZvE7EwP4e56xg/s1600/sem1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="187" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmlAarkMnSUXE0ZKwuhLwJL7XUCbQi86hZoFiEZN2sZKWg-w8oprZHmYzh6nDqQOdEcZ_CMrTeITgrx5WqtIg-U_Y_m8ryq5kALJ69H8nWKB8BJfLyaXHjUh4s_-f8a1ZvE7EwP4e56xg/s400/sem1.png" width="400" /></a></div>
<br />
<br />
In the picture you can see that while the system is Idle (green line) a semaphore is posted (first green flag) by the Hwi function.<br />
Control is handed over the mailbox management function (higher blue line) which is pending on the semaphore (first red flag).<br />
It executes toggling the msg.val and then posts a mail (second green flag), then goes back pending on the semaphore again (second red flag).<br />
Only then the bios scheduler (lower blue line) passes the control over to the ledToggle function (red line) which is pending on the mailbox, it gets the message (third green flag -it is green because it does not block the task, and it does not block the task because there is a message in the mailbox), manages the led based on the value in the message and finally waits again for the mailbox (third red flag).<br />
At this point there are no other messages in the mailbox, so the flag is red, the task gives back control to the sceduler.<br />
Guess what happens when a new timer int is fired?<br />
Yup, rinse & repeat.<br />
<br />
Neat eh?<br />
If you are interested in knowing more on the subject, I encourage you to try the <a href="http://processors.wiki.ti.com/index.php/Introduction_to_the_TI-RTOS_Kernel_Workshop" target="_blank">free TI RTOS Workshop</a>, the example illustrated here (and the relative code) is taken from the Lab 9 material.</div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-70072172723426080402015-08-06T19:06:00.001+02:002015-08-10T10:11:55.919+02:00Playing with the TI-RTOSI always thought that dealing with an RTOS was some kind of nightmare.<br />
Well, looks like I was wrong and yet again we prove that most of our beliefs are generated by ignorance, I happen to have a lot of it! :)<br />
<br />
First thing first, what is an RTOS?<br />
<br />
Real Time Operating System, that's what the acronym stands for, but to give a better explanation, we can say it is an <b>Operating System </b>that runs on micro-controllers and eventually CPUs.<br />
That's the "OS" part, now for the "RT" one we can say that it is designed to have a minimal overhead and allow, depending on the clock cycle of the used hardware device, a quick reaction to events.<br />
<br />
Say you want to control an electric motor and you feed back a number of signals (i.e. actual speed from an <a href="https://www.blogger.com/"><span id="goog_1492550333"></span>hall effect sensor<span id="goog_1492550334"></span></a> , some user controls etc.), then you want the system to react as "realtime" as possible, you don't want you motor to react 5 minutes later because you are installing some windows updates.<br />
<br />
Yup, you should not expect live updates by default in an RTOS :)<br />
<br />
When you have many things potentially happening at the same time, then you normally use a loop that scans them (the quick and dirty solution) or better you set up some interrupts and maybe some timer based functions.<br />
<br />
If you have an OS, then you can use <b>threads</b>.<br />
An RTOS gives you the ability to schedule threads, neat eh?<br />
However in giving you that functionality it makes sure that this does not generate much overhead and it allows you to define how to prioritize them.<br />
<br />
If you played with systems running with multiple interrupts, then you know about nesting interrupts and while <u>in theory</u> this is pretty straight forward, but in an application that should not miss any interrupt and provide a reliable event handling this can be problematic.<br />
<br />
You guessed, the RTOS threads make this an easier task.<br />
<br />
... but... yeah... when I am dealing with an mcu I might not have much of power to run an OS you may think.<br />
Well, the tiny MSP430G2 runs at 16Mhz, 16 bits, not much, right?<br />
My old 80286 desktop computer was 16 bit , 10MHz and I thought it was running MS-DOS pretty neatly!<br />
So, in reality, it depends on the OS you are using and an RTOS gives you WAY LESS than MS-DOS, and this makes it perfectly usable even on a MSP430 launchpad (don't try to install windows 10 on it, tho)!<br />
<br />
TI created its own RTOS (and they called it TI-RTOS) and it is available for different kind of platforms : MSP430, CortexM4 (Stellaris, Tiva), C28x, C6x etc.<br />
<br />
If you have any kind of launchpad, chances are you can freely use the TI-RTOS!<br />
In CCS6.1.0, just go to the CCS App Center and download the version that matches your device<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzUpZ8jlbHzSbYAohhLXnwvDZ_JCFBnCxwXSa-Wszfho-T7zRjant1EeTPxOf4xp1MDtxZvFlGmrzKnCzggFn1fWtkGGQpNdWRHsKKu7CgWoYy15g0sGbtrwASdzLexmHPnI5QYOFiS5o/s1600/tirtos_install.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzUpZ8jlbHzSbYAohhLXnwvDZ_JCFBnCxwXSa-Wszfho-T7zRjant1EeTPxOf4xp1MDtxZvFlGmrzKnCzggFn1fWtkGGQpNdWRHsKKu7CgWoYy15g0sGbtrwASdzLexmHPnI5QYOFiS5o/s400/tirtos_install.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
As in its best tradition, TI provides amazing training material, including an extremly well done workshop (yup, for free, online) titled "<a href="http://processors.wiki.ti.com/index.php/Introduction_to_the_TI-RTOS_Kernel_Workshop" target="_blank">Introduction to the TI RTOS Kernel Workshop</a>".<br />
The instructor Eric Wilbur is absolutely great in <a href="https://training.ti.com/ti-rtos-workshop-series-introduction?cu=7475" target="_blank">those videos</a>.<br />
Lab activities help tremendously in understanding the tasks at hand and in discovering how much you can do with the OS and the related tools.<br />
<br />
We said the RTOS has some kind of smart "scheduler" that allows you to run threads, but that's just a small (although important) part of it.<br />
It provides memory management, debug functionality and GUI configuration features. <br />
Also it comes with drivers, provided in a library, these reduce the need to access the system low level, instead they give you APIs you can use to interact with the rich hardware present in the MCUs.<br />
<br />
I am currently enjoying the labs of the workshop, I suggest you do the same, but for those who are too lazy for it, I will post here some summary activity, this will be my way of taking minutes about what I do.<br />
<br />
Meanwhile, if you think a typical "arduino like" application, it has a skeleton like the following<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void init()</span><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> // hw initialisation</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">void loop()</span><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> while (1)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> dosomeStuff();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> doSomeOtherStuff();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
<br />
a TI RTOS application instead looks like :<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void main(void)</span><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> hardware_init();// init hardware via Xware</span><br />
<span style="font-family: Courier New, Courier, monospace;"> BIOS_start();</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
<br />
There is no more a <b>while(1)</b> loop because the BIOS is handling the task scheduling, you simply ask the bios to start and it will take care of the different threads.<br />
Threads exist in different flavors and they can be assigned different priorities.<br />
The easiest form of a thread is an idle function, which is executed with the lowest priority by the idle thread, basically when the CPU / MCU does not have anything more important to do.<br />
<br />
Creating an idle function is fairly easy, say we have a function that toggles the onboard LED (code taken from lab 4 of the before mentioned workshop and slightly modified by myself)<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void ledToggle(void)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_3))</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>GPIOPinWrite(GPIO_PORTF_BASE, </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>else</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>GPIOPinWrite(GPIO_PORTF_BASE, </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> GPIO_PIN_3, GPIO_PIN_3);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>delay()<span class="Apple-tab-span" style="white-space: pre;"> </span>// create a delay of ~1/2sec</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<br />
then you just need to register the function as an idle, which you can do in the GUI simply like this :<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu2mpLkx56gkFm-6uCaH9XNhL4GOXACXbZQkmxOFrOSX3F6AkUj-J5YtIuqWxT6h3KFfp9JZebOaSNsSqn-eIbxs_bdfAVCZ_X2KhyphenhyphenoXrSCZd1vkm-6ER1-H2FhCrHvARZd-wAfgRT5vA/s1600/idle1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu2mpLkx56gkFm-6uCaH9XNhL4GOXACXbZQkmxOFrOSX3F6AkUj-J5YtIuqWxT6h3KFfp9JZebOaSNsSqn-eIbxs_bdfAVCZ_X2KhyphenhyphenoXrSCZd1vkm-6ER1-H2FhCrHvARZd-wAfgRT5vA/s320/idle1.png" width="320" /></a></div>
Pretty simple eh?<br />
Now, you may think that the delay function call is blocking, but this "blocking" behavior only affects <u><b>this specific thread</b></u>, it does not prevent other threads, with higer priority, to run in parallel.<br />
<br />
Now I guess you can see how the whole OS thing starts to make sense and at the same time, it does not necessarily add complexity to your application.<br />
<br />
Give it a try, it's fun!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/RPN60VitGc4/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/RPN60VitGc4?feature=player_embedded" width="320"></iframe></div>
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-87702433348062155252015-07-31T09:32:00.000+02:002015-07-31T09:57:32.490+02:00Internet of Things, sub 1GHz radio and moreIf you follow my blog, you probably realized that I am a supporter of technology company that engage in quality education activities.<br />
<br />
Texas Instruments is one of them, so I used some of their products to learn and to share my experiments in this blog.<br />
<br />
Not long ago (July 16th 2015) TI, together with Element14, offered an interesting <a href="http://www.element14.com/community//events/4379" target="_blank">free webminar</a> with the captivating title : "<b><i>From Start to Finish: Creating a Multi-Node Cloud-Connected Sensor Network with Texas Instruments LaunchPad Development Kits</i></b>"<br />
<br />
I know, now you are expecting a "...but...".<br />
Nope, no "but", it was simply great, I strongly suggest you check it :)<br />
<br />
IoT is becoming easier and easier, both from software and hardware point of view.<br />
Software is kind of my thing, so, that was never really a main issue for me, or better it was an issue I knew how to deal with, but hardware used to be either hard or expensive (or both).<br />
Gone are those days and there are plenty of products (from various vendors) that really speed up your prototyping.<br />
<br />
TI definitely supprots them with great learning resources, this webinar, presented by <b>Adrian Fernandez</b> , TI Microcontroller Development Experience Manager was one of them.<br />
<br />
You can see his video here:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/8ypTFqkLFO0/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/8ypTFqkLFO0?feature=player_embedded" width="320"></iframe></div>
<br />
Now, the IoT part is cool, but combining it with sub1GHz radio is even better (and as Adrian shows, quite easy).<br />
<br />
So, IoT means you have some device that can communicate with the internet, usually acting as a node connected to an ADSL router.<br />
If you have 10 sensors spread around your house, you can definitely have 10 nodes, all connecting to your router and doing their stuff.<br />
It works, possibly, but it's not the best solution.<br />
Back in the days we used to add a RS485 interface, run a few cables here and there and generate a wired network of sensors to the "managing" node, the one that eventually communicates with the internet.<br />
Also works.<br />
Then the nRF24L01 radio came out, working at 2.4GHz.<br />
That one is cool, low cost, not too difficult to use.<br />
<br />
Can we do even better?<br />
Turns out we can.<br />
The <a href="http://www.ti.com/product/cc1101" target="_blank">TI CC110L</a> chip allows Radio communication at 433MHz (and other sub 1GHz frequencies), for wireless connectivity in a low power package and low frequencies give you more "bang" for your milliAmps.<br />
TI provided a <a href="http://www.ti.com/tool/cc1101emk433" target="_blank">boosterpack</a> for the launchpads featuring this chip, that makes it easier to implement a prototype, particularly because being part of their standard ecosystem, it comes with software libraries.<br />
This is the boosterpack FedEX delivered few minutes ago :<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBFSRvNT7vVV6Fe9HI2LDmHT3Is6GqoPq3uRceB1EPtN3pujlOC1nOuh3dCyht6fQBWvUVuzPwf29LKPxFLqvm855DR7kHGR2k3ppVt8Nok4jSl0ABhqywY07CWXpgZqgtLaC0cjaQRps/s1600/C110.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBFSRvNT7vVV6Fe9HI2LDmHT3Is6GqoPq3uRceB1EPtN3pujlOC1nOuh3dCyht6fQBWvUVuzPwf29LKPxFLqvm855DR7kHGR2k3ppVt8Nok4jSl0ABhqywY07CWXpgZqgtLaC0cjaQRps/s400/C110.jpg" width="400" /></a></div>
<br />
The Kit gives you two CC110 (@433MHz) nodes on a shield.<br />
Now, why did I receive the boosterpack?<br />
<br />
Well, in my personal opinion this story redefines the concept of "cool".<br />
So, I joined this free webinar, which was extremely informative and fun, extremely "hands-on".<br />
That, in my book, is "cool".<br />
TI delivers free software tools and rather cheap hardware to play with and practice what you learnt, that's also cool, no?<br />
<br />
But what goes behind the concept of cool is that I got the boosterpack, plus a MSP430FR5969 launchpad AND a CC3200 Wi-Fi launchpad FOR FREE, delivered from Texas to the old continent.<br />
<br />
Apparently I got lucky (not sure how many winners were there), but simply answering a very short quiz after the webinar I won all those toys.<br />
It's Christmas in July! :)<br />
<br />
I am currently extremely busy with a couple of projects, but as soon as I can spare some time (hopefully really soon), I plan to test the new toys in an industrial automation project, collecting production data from machines and pushing them to the web.<br />
I am currently using a BBB for that, but there is a case for a different architecture, possibly on top of the existing one.<br />
<br />
Until then, well, thanks Adrian and TI!<br />
<br />
<br />
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-35897725145273414302015-06-13T09:48:00.000+02:002015-07-08T18:54:49.813+02:00Should rights be "forever" in a ever-changing world?<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: justify;">
We fight for our rights, many, if not most, of our heroes are those who gave their lives to obtain and preserve some rights we now hold dear.</div>
<div style="text-align: justify;">
These include freedom, equality (Liberté, égalité, fraternité anyone?) down to some more modern era/more detailed and specific rights such as (in some countries) refuse to join an army, work-life balance, health, even a minimum wage or a "citizenship income" in some places etc.</div>
<div style="text-align: justify;">
People should not work more than 8 hours a day (may vary slightly by country).</div>
<div style="text-align: justify;">
Took a while to achieve that and we consider it an important milestone in human rights.</div>
<div style="text-align: justify;">
I am all for it, don't get me wrong, in fact it might even be the case we should at this point (some did) reduce those 8 hours.</div>
<div style="text-align: justify;">
But, what IF it does not make anymore sense, meaning that in a given context, a given society, that does not work anymore, it is not sustainable.</div>
<div style="text-align: justify;">
Would it be still a right?</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now, the one I would like to discuss is even more radicated in our culture, in a way that every single politician in every single campaign would advertise he/she will do everything to boost it.</div>
<div style="text-align: justify;">
Politicians do their research (with our money) and even the dumbest of them are able to select their stands on these topics, so I know I will attract a lot of hatred reactions just for discussing the matter, but, hey, go ahead, hating is one of your rights after all (and I am not running for office anytime soon) :)</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The right to have a family.</div>
<div style="text-align: justify;">
Ok, ok, I hear you booing already, once you are done, can we have a serious discussion about it?</div>
<div style="text-align: justify;">
The "light" version of it says that a men and a woman should be able to marry.</div>
<div style="text-align: justify;">
A slightly modernized version says that two humans, regardless of their sex and their sexual preferences, should be able to marry.</div>
<div style="text-align: justify;">
I am fine with both versions, no issues here.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now, in most places this extends to "a family" in the sense you have rights to have children.</div>
<div style="text-align: justify;">
Children are cool I guess, who could argue with that?</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Before we go ahead, I know in these discussions we are all biased, so I will just declare my bias upfront, for the benefit of a rational and honest discussion :</div>
<div style="text-align: justify;">
<i>I have no children, never married, never wanted to, never felt the urge to create a family, for a number of different reasons.</i></div>
<div style="text-align: justify;">
At this point I guess you MUST be hating me a little bit already, right?</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Ok, now, back to the point.</div>
<div style="text-align: justify;">
Rights to have children in general means a lot of things which go beyond the actual fact of having one or more babies.</div>
<div style="text-align: justify;">
It ties into making it easier to families to support them, in other words it is like the society is promoting families.</div>
<div style="text-align: justify;">
In most countries the society recognizes that raising children is an expensive task, so you get a little bit of tax reductions, some maternity leave rights (for both parents) etc.</div>
<div style="text-align: justify;">
These "allowances" are granted using the society resources (mainly collected taxes) as in general such resources should go to support the citizen's rights and well being.</div>
<div style="text-align: justify;">
If something is a citizen's right, then I totally agree that the society should do whatever possible to favour its implementation and even promote it.</div>
<div style="text-align: justify;">
But is it?</div>
<div style="text-align: justify;">
Is transmitting your DNA really a right and, in a more general sense, can we say that a right is still a right regardless of the context, forever?</div>
<div style="text-align: justify;">
Or can we say that rights are a mere product of our culture, which, in turn, generates from our history?</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Let me introduce another bias I have : <i>I am an atheist (which I find a funny definition, but most of you would call me that way) and have no holy book telling me what's good or wrong. I do need to find it out myself and for this reason I ask myself several questions and sometimes discuss them with others.</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
So, it is clear that the urge of transmitting our DNA is present in all animal species, but normally they (slowly) evolve, both genetically and "culturally" in a way that affects their reproduction rate according to the needs.</div>
<div style="text-align: justify;">
A wonderful explanation of this concept (although with the opposite problem) can be found in the speech that Douglas Adams gave for TED, about 1 third in the speech, when he tells the story of the Kakapo.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I strongly encourage you to watch the full speech as D.A. was a phenomenal speaker on top of being a witty and creative writer.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/_ZG8HBuDjgc/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/_ZG8HBuDjgc?feature=player_embedded" width="320"></iframe></div>
<br />
<div style="text-align: center;">
<span style="font-family: inherit; font-size: x-small;"><i>(Douglas Adams : "Parrots, the universe and everything")</i></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The "problem" with humans is that we became remarkably efficient in modifying the environment around us to suit our needs, so, when the environment was supposed to counter our expansion, we fought back and somehow "won".</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Going from the Kakapo to another animal that might be more familiar to all of us, let's consider the cat.</div>
<div style="text-align: justify;">
I love cats, in fact <a href="http://fortytwoandnow.blogspot.ch/2012/09/some-mice-are-smarter.html" target="_blank">I live with two 10 yr old females</a> since quite some time.</div>
<div style="text-align: justify;">
Most of the people who love cats agrees -like I do- that it is a good thing to spay or neuter them.</div>
<div style="text-align: justify;">
In the wilderness, the chances of survival of a cat in his/her first years are pretty slim, plus when the populatuion grows in a given area, it is regulated by competition for food or territory.</div>
<div style="text-align: justify;">
So they needed to procreate very quickly, the fittest would generally survive and maintain the specie alive.</div>
<div style="text-align: justify;">
Since most of the cats now live with humans, they share the "benefits" of the modified environment, i.e. we provide medical care and food for them which extends greatly their life expectaion and dramatically reduces chances of deaths for lack of food etc.</div>
<div style="text-align: justify;">
Is the cat risking extinction because we neuter and spay most of them?</div>
<div style="text-align: justify;">
Not that I am aware of, in fact it seems to me that population control, given the actual context, is being a benefit for the cat specie.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now, why would it be different for humans?</div>
<div style="text-align: justify;">
Take a look at this chart :</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiQRRDLQ57FsphrJL3-PIU4IKRGsxhbDCLhJnh-yoZGgVko106C3Y3xo1IjGUjrRig2aiiGrPkYoOg2RQrhWaQbXJgtooOVPaTPEeMG5XyHa5bDr_HM7QYQDYJDs4AgA16ABbtBZkG_CQ/s1600/worldpopgr.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiQRRDLQ57FsphrJL3-PIU4IKRGsxhbDCLhJnh-yoZGgVko106C3Y3xo1IjGUjrRig2aiiGrPkYoOg2RQrhWaQbXJgtooOVPaTPEeMG5XyHa5bDr_HM7QYQDYJDs4AgA16ABbtBZkG_CQ/s400/worldpopgr.gif" /></a></div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Does anybody see any alarming trend there?</div>
<div style="text-align: justify;">
Humans in 1960 : 3.000 Millions</div>
<div style="text-align: justify;">
Humans in 2050 (projection) : 9.000 Millions</div>
<div style="text-align: justify;">
( 3x in 90 years)</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Cat's chart would have been similar (worse actually, because of their high reproduction rate) if we did not take actions. We realized that having an average of 3 cats per square meter aound us would have been quite an issue for everybody, including them.</div>
<div style="text-align: justify;">
Cats have no right to procreate in fact, it did not take long to us to negate that one to them, few complained.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now, back to humans, I believe it is culturally difficult to "cap" the number of children a family should have (it is somehow happening in some places), mainly because we feel that having them is a right.</div>
<div style="text-align: justify;">
For the same reason we still try, as a society, to encourage families to have children.</div>
<div style="text-align: justify;">
But, does it make sense?</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Shouldn't a behavior that actually damages the society, the human kind and the whole world alltogether be considered more like a crime, rather than a right?</div>
<div style="text-align: justify;">
I know this is a strong statement, but it is really a question.</div>
<div style="text-align: justify;">
I am not immune to cultural biases either, so that question scares me as well.</div>
<div style="text-align: justify;">
But I do know that sometimes truth can be scary, because it shakes our belief system, but I grew accustomed to this, I know that scary or not does not change the fact that it <u>is</u> the truth.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I also imagine many of you will say things like : "If your parents thought the same thing, you would not be here blogging" and yes, I can see that, but, so what?</div>
<div style="text-align: justify;">
Isn't this an incredibly egoistic thing to say?</div>
<div style="text-align: justify;">
Each one of us feels special, but from the community point of view we are just another human contributing both with good and bad interactions.</div>
<div style="text-align: justify;">
I try my best, most of the time, to ensure that my contribution to the society is worth the air I breathe and the food I eat, sometimes I question it (and I believe that's a good exercise).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Can our society still consider that having babies is a human right?</div>
<div style="text-align: justify;">
Should rights be demoted to "cultural habits" and eventually to "bad habits coming from a past, different, context" when they damage the society?</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Pick your answer and try to be consistent with facts.</div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com2tag:blogger.com,1999:blog-3747970306027691432.post-39302330926631272092015-05-21T09:36:00.000+02:002015-05-21T09:36:12.825+02:00Cortex M3 - SPI / 1I have been playing with SPI <a href="http://fortytwoandnow.blogspot.com/2012/07/msp430g2-usci-spi-interface-1.html" target="_blank">a few times</a>, but never on a Cortex M3 using CMSIS.<br />
<br />
That, by itself, it should be a good reason to dig into this topic, however I have a nice project in mind and it will require SPI communicatin, so... let's get to it!<br />
<br />
Some basic stuff first :<br />
SPI uses four pins: MOSI (Master Out Slave In), MISO (you guess it), CLK (clock) , SSEL and as Chip enable/select to activate the slave, normally a simple GPIO pin on the master.<br />
<br />
NXP Cortex M3s implement a variation of SPI called <a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0303e/Cacbaedb.html" target="_blank">SSP (Synchronous Serial Port)</a> which supports the "old" SPI.<br />
In the LPC1768 there are two SSP peripherals called SSP0 and SSP1.<br />
<br />
The LPC17xx manual says:<br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;">"The two SSP interfaces, SSP0 and SSP1 are configured using the following registers:</span><br />
<br />
<ol>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"><b>Power: </b>In the PCONP register, set bit PCSSP0 to enable SSP0 and bit PCSSP1 to enable SSP1.<br />Remark: On reset, both SSP interfaces are enabled (PCSSP0/1 = 1).</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"><b>Clock: </b>In PCLKSEL0 select PCLK_SSP1; in PCLKSEL1 select PCLK_SSP0. In master mode, the clock must be scaled down.</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"><b>Pins: </b>Select the SSP pins through the PINSEL registers and pin modes through the PINMODE registers.</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"><b>Interrupts: </b>Interrupts are enabled in the SSP0IMSC register for SSP0 and SSP1IMSC register for SSP1. Interrupts are enabled in the NVIC using the appropriate Interrupt Set Enable register.</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"><b>Initialization: </b>There are two control registers for each of the SSP ports to be configured: SSP0CR0 and SSP0CR1 for SSP0, SSP1CR0 and SSP1CR1 for SSP1.</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"><b>DMA: </b>The Rx and Tx FIFOs of the SSP interfaces can be connected to the GPDMA controller </span></li>
</ol>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;"><b>Remark: </b>SSP0 is intended to be used as an alternative for the SPI interface, which is included as a legacy peripheral. Only one of these peripherals can be used at the any one time" </span><br />
(<a href="http://www.nxp.com/documents/user_manual/UM10360.pdf" target="_blank">@NXP LPC17xx user manual</a>)<br />
<br />
It seems to me this is a pretty good checklist.<br />
<br />
<b>1) Power ON</b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcE1xi_eA9nZXzPpzNw6g6KMyKvAoe0_7GwkYWh4aDooBnXSN5F5RC1bIcNo7QOEqsnM_Gva10-mv-RUbUar_3WFPlRwks9cw9iXIwAnEE67V623p2LMkjqKajsY4uUuUYEs_-J4E3a9I/s1600/pconp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcE1xi_eA9nZXzPpzNw6g6KMyKvAoe0_7GwkYWh4aDooBnXSN5F5RC1bIcNo7QOEqsnM_Gva10-mv-RUbUar_3WFPlRwks9cw9iXIwAnEE67V623p2LMkjqKajsY4uUuUYEs_-J4E3a9I/s640/pconp.png" width="532" /></a></div>
<br />
Power CONtrol for Peripherals (<b>PCONP</b>) is the register we use to turn the SSP (or any other) interfaces on:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_SC->PCONP |= (1 << 21); /* Enable power to SSPI0 block */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_SC->PCONP |= (1 << 10); /* Enable power to SSPI1 block */</span><br />
<br />
Normally we just need one, I reported the lines for both so you can decide which one to use.<br />
<br />
<b>2) Clock in</b><br />
<br />
The Peripheral clock selection is done via the <b>PCLKSEL0</b> and 1.<br />
Each peripheral uses 2 bits<br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;">00 : PCLK_peripheral = CCLK/4 00</span><br />
<span style="color: #ffd966; font-family: Arial, Helvetica, sans-serif; font-size: x-small;"><b>01 : PCLK_peripheral = CCLK</b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;">10 : PCLK_peripheral = CCLK/2</span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: x-small;">11 : PCLK_peripheral = CCLK/8</span><br />
<br />
SSP0 uses bits 11:10 of PCLKSEL1 and SSP1 uses bits 21:20 of PCLKSEL0<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SC->PCLKSEL1 &= ~(3<<10); /* PCLKSP0 = CCLK/4 */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SC->PCLKSEL1 |= (<b><span style="color: #f1c232;">1</span></b><<10); /* PCLKSP0 = CCLK */</span><br />
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SC->PCLKSEL0 &= ~(3<<20); /* PCLKSP1 = CCLK/4*/</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SC->PCLKSEL0 |= (<b><span style="color: #f1c232;">1</span></b><<20); /* PCLKSP1 = CCLK */</span></div>
<div>
<br /></div>
<div>
<b>3) Pins</b></div>
<div>
<br /></div>
<div>
Here we will set MISO, MOSI and CLK pins, plus you need to remember to set 1 GPIO as output to enable the slave, in this example we will assume you are using GPIO P1.21 as SSEL (Slave Selection / Enable).</div>
<div>
Normally SPI slaves are selected active when SSEL is LOW.</div>
<div>
<br /></div>
<div>
A summary of the available configurations for SSP pins :</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcjVXNJ98C5-iB9f2HZ5qR_RNMQ-Cil9Q5HEVybiXksqLDrHuX4mLsxUQGWcOWmoDPRaI2V1XuOJYhNWU0fs8fP7e2oABFKRY_P_4hz-XqpnMcrMLIYMisBE4swLat2Yv5evP9BO53x4k/s1600/ssppins.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcjVXNJ98C5-iB9f2HZ5qR_RNMQ-Cil9Q5HEVybiXksqLDrHuX4mLsxUQGWcOWmoDPRaI2V1XuOJYhNWU0fs8fP7e2oABFKRY_P_4hz-XqpnMcrMLIYMisBE4swLat2Yv5evP9BO53x4k/s400/ssppins.png" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> <i>/* </i></span><i style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">----> </i><i style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">SSEL : output set to high. */</i><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_PINCON->PINSEL3 &= ~(0<<10); /* P1.21 SSEL (used as GPIO) */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_GPIO1->FIODIR |= (1<<21); /* P1.21 is output */</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;">LPC_GPIO1->FIOPIN</span><span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"> </span><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> |= (1<<21); /* set P1.21 high*/</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> <i>/* </i></span><i style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">----> </i><i style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">SSP0 : SCK, MISO, MOSI */</i><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_PINCON->PINSEL3 &= ~(3UL<<8); /* P1.20 cleared */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_PINCON->PINSEL3 |= (3UL<<8); /* P1.20 SCK0 */</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"> /* P1.23, P1.24 cleared */</span><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_PINCON->PINSEL3 &= ~((3<<14) | (3<<16)); </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"> /* P1.23 MISO0, P1.24 MOSI0 */</span><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_PINCON->PINSEL3 |= ((3<<14) | (3<<16)); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> <i>/* </i></span><i style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">----> </i><i style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">SSP1 : SCK, MISO, MOSI */</i><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_PINCON->PINSEL0 &= ~(0x3F<<14); /* P0.7,8,9 cleared */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> /* ... an then set to function 2 */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_PINCON->PINSEL0 |= (2UL<<14) | (2UL<<16) | (2UL<<18);</span><br />
<br />
<b>4) Interrupts</b><br />
<br />
As suggested by the checklist, we will use the SSP Interrupt Mask Registers <b>SSPxIMSC</b>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh44j7lzyv428Wgp6WL8G7RXgvliUidFk3dDCMhBV5pKtSQ-tUyyoOm_wGerHRe6QgQGfoJstMDouWqLcFIBYKiCRE4b-DMTybDz8UCs14_Y5ZxYru9mHS8WRNTSlVTh1qrsy6jZRvxlYQ/s1600/sspxim.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh44j7lzyv428Wgp6WL8G7RXgvliUidFk3dDCMhBV5pKtSQ-tUyyoOm_wGerHRe6QgQGfoJstMDouWqLcFIBYKiCRE4b-DMTybDz8UCs14_Y5ZxYru9mHS8WRNTSlVTh1qrsy6jZRvxlYQ/s400/sspxim.png" width="400" /></a></div>
<br />
As you can see, these interrupts are used to identify error conditions or FIFO status to ease buffered communication.<br />
Since SSP is a synchronous communication (unlike the UART), there is no point in having a RX data ready interrupt.<br />
In fact, each time you want a slave device to send you some data, using SPI / SPSS you explicitly have to ask for it (polling), meaning you should also be already listening for it to arrive, no need for an interrupt.<br />
<br />
Should you need to implement some more advanced control, feel free to enable those interrupts, in that case you should check the <b>SSPxRIS</b> (Raw Interrupt Status), <b>SSPxMIS</b> (Masked Interrupt Status) and <b>SSPxICR</b> (Interrupt Clear) registers.<br />
<br />
<b>5) Initialisation</b><br />
<br />
Ok, we definitely need this one.<br />
What we need here is to accurately set the bit frequency, so that it will match the frequency supported by the slave device we are interfacing.<br />
This is done via the Prescaler Register (CPSR) that divides the peripheral clock (pclk) we initially configured in step 2 (PCLKSEL0 and 1).<br />
<br />
So, let's assume our processor is running at 100MHz, we fed the peripheral with the same clock speed (by providing a divider = 1) and now we want to obtain a 400KBit/s rate.<br />
How do we do that?<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#define sspKBps 400000</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">int prescaler = SystemCoreClock / sspKBps; </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">/* 100.000.000/400.000 = 250 */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SSP0->CPSR = prescaler; /* for SSP0 */</span><br />
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SSP1->CPSR = prescaler; /* for SSP1 */</span></div>
<div>
<br /></div>
<div>
Now we need to use the SSP Control registers to specify how many bits should be transferred and which protocol -Frame Format- to use (remember, the SSP can do more than SPI, in fact it supprots TI and Microwire formats too). </div>
<div>
Also, we can further reduce the bit rate here by dividing the value of the prescaler, plus we can set clock phase and polarity.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbfugNn8kyRQitgleCeOq49uSvBYSiwkJBJdlFxkUvaY3WjQbaP3Y0C3w_yPIvwRQwuwP6WjrOWt_-Vk7qaa8Lqab58OAkb2C1LXomkrGz3Ec1gWIVIgD2inENK97V8Dsglxs570Epmek/s1600/sspcr0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbfugNn8kyRQitgleCeOq49uSvBYSiwkJBJdlFxkUvaY3WjQbaP3Y0C3w_yPIvwRQwuwP6WjrOWt_-Vk7qaa8Lqab58OAkb2C1LXomkrGz3Ec1gWIVIgD2inENK97V8Dsglxs570Epmek/s640/sspcr0.png" width="457" /></a></div>
<div>
</div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><i>/* SSP0 : 8Bit, SPI, CPOL=0, CPHA=0 */ </i> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SSP0->CR0 = 0x0007; </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><i>/* SSP1 : 8Bit, SPI, CPOL=0, CPHA=0 */ </i></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SSP1->CR0 = 0x0007; </span><br />
<br />
The Control Register 1 (CR1) allows to enable the SSP port and to configure it as master or slave.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2BMTK69MDOnpAEog-63LR1g0msnlGZcVgOY9PZ5U7G52tF_mnHiAc6jbgs3YVq-M2SoZgmpCUMGpBS1_vTY7KXA_EMXk0sANESnZHcQQWrV6poF2L08xFY9ZFMYk9K2mIxqXmtNbnkKg/s1600/ssp0cr1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2BMTK69MDOnpAEog-63LR1g0msnlGZcVgOY9PZ5U7G52tF_mnHiAc6jbgs3YVq-M2SoZgmpCUMGpBS1_vTY7KXA_EMXk0sANESnZHcQQWrV6poF2L08xFY9ZFMYk9K2mIxqXmtNbnkKg/s400/ssp0cr1.png" width="400" /></a></div>
<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SSP0->CR1 = 0x0002; /* SSP0 enable, master */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SSP1->CR1 = 0x0002; /* SSP1 enable, master */</span></div>
<div>
<br /></div>
<b>6) DMA</b><br />
<br />
I am sure some day I will feel particularly brave and will have a go at it, for now, let's just say that we can enable DMA transfers for SSP ports using the <b>SSPxDMACR</b> registers.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEij07CRQJaLiPmREr5uDnOo6uSz2qArlYicNmSJOZzbEyPmkIVMFH6lwX1xXp0EBnda6rPHceJ3fX0KQyP2JSzKxqnEiUHGveOmU9bDkgDkQQxGwJB8ble8SHrKZNMuifqh8KHGUdrbv0A/s1600/sspdma.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEij07CRQJaLiPmREr5uDnOo6uSz2qArlYicNmSJOZzbEyPmkIVMFH6lwX1xXp0EBnda6rPHceJ3fX0KQyP2JSzKxqnEiUHGveOmU9bDkgDkQQxGwJB8ble8SHrKZNMuifqh8KHGUdrbv0A/s640/sspdma.png" width="640" /></a></div>
<br />
<br />
Ok, with all this our SSP port should be ready for communication, at least on the Master side.<br />
<br />
So, where do we put output data and from where do we get input?<br />
There is a Data Register <b>SSPxDR</b> (we can use the low 16 bits) that is used both for RX and TX.<br />
Why is this possible?<br />
SSP (or SPI) is synchronous communication, meaning you cannot write and read at the same time on the line, or better, for every byte you send out, you will get a byte back.<br />
<br />
The LPC17xx manual says :<br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">"<b>Write</b>: software can write data to be sent in a future frame to this </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">register whenever the TNF bit in the Status register is 1, indicating that </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">the Tx FIFO is not full. If the Tx FIFO was previously empty and the </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">SSP controller is not busy on the bus, transmission of the data will </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">begin immediately. Otherwise the data written to this register will be </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">sent as soon as all previous data has been sent (and received). If the </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">data length is less than 16 bits, software must right-justify the data </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">written to this register.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;"><b>Read</b>: software can read data from this register whenever the RNE bit </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">in the Status register is 1, indicating that the Rx FIFO is not empty.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">When software reads this register, the SSP controller returns data from </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">the least recent frame in the Rx FIFO. If the data length is less tha</span><span style="font-family: Arial, Helvetica, sans-serif; font-size: xx-small;">n 16 bits, the data is right-justified in this field with higher order bits filled with 0s"</span><br />
<br />
Looks like we need to check the Status Register (<b>SSPxSR</b>)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE6XwvgymNvy8dFZ6Z8XKJ2rEq7rneTwxT5mvH30wc7gVKrsmuoE-RxxxKCLdweC4IpvOvd-3Ta5ZtWu0xKgeuy_63tLRb4XCVZubEQf8UY-YmL4iGWWAhaDd-0F_Z1P_4NWCx3d8b9oY/s1600/ssp0sr.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="187" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE6XwvgymNvy8dFZ6Z8XKJ2rEq7rneTwxT5mvH30wc7gVKrsmuoE-RxxxKCLdweC4IpvOvd-3Ta5ZtWu0xKgeuy_63tLRb4XCVZubEQf8UY-YmL4iGWWAhaDd-0F_Z1P_4NWCx3d8b9oY/s400/ssp0sr.png" width="400" /></a></div>
<br />
So, putting it all together, to exchange 1 byte we need to :<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">int<b> SSP1_sendbyte</b>(int out)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">// enable your GPIO used as SSEL</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_GPIO1->FIOCLR = 1<<21; // enable slave</span><br />
<i style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // while(!(LPC_SSP1->SR & 1)) ; // Wait until TX Empty</i><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> // might need a grace period here, depending on the slave</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_SSP1->DR = out; // output data</span><br />
<i style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> // while(LPC_SSP1->SR & (1 << 4)); // Wait until SSP is busy</i><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> while(LPC_SSP1->SR & (1 << 2)); // Wait until we have data in RX</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_GPIO1->FIOSET = 1<<21; // disable slave</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return LPC_SSP1->DR;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<br />
In a future post we will test this with some SPI device.<br />
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-58377154849677097842015-05-19T21:21:00.001+02:002015-05-19T21:21:30.241+02:00Cortex M3 - UART / 2Interrupts are cool.<br />
No, seriously, if you played with serial communications you know that using an ISR helps a lot because you never know when the other device decides to send a few bytes on the line.<br />
Asynchronous communication in full duplex baby!<br />
<br />
So it is good to have an Interrupt Service Routine that gets the data for you from the line while you are busy doing other things.<br />
Typically you are going to have a buffer with two pointers: one knows where to find the first location in the buffer where to write data and the other knows the first location where you did not get data out of the buffer yet.<br />
If the two pointers point to the same lcoation, then there is no data to be extracted from the buffer.<br />
<br />
In general this is a convenient way to buy some time and check every now and then if we received some data.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq8A2FgmIYYxdYMGm1n7mcybwa_bwGf1MVtLIskijEiScWdU-rZJgso6QBbpTQ_iA8Im2kkX5pIg6nQMpqThJ2rDOt1twaRjFFvExx7oIBq93qXP9vXcaNfn-5K4_QVK98b3oLNNWHeyw/s1600/buffer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="164" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq8A2FgmIYYxdYMGm1n7mcybwa_bwGf1MVtLIskijEiScWdU-rZJgso6QBbpTQ_iA8Im2kkX5pIg6nQMpqThJ2rDOt1twaRjFFvExx7oIBq93qXP9vXcaNfn-5K4_QVK98b3oLNNWHeyw/s320/buffer.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In the image above you can see an example where 3 bytes were received, so the write pointer points to the 4th location and 1 byte was read from the buffer, so the Read Ptr points to the 2nd location.</div>
<div class="separator" style="clear: both; text-align: left;">
The two pointers have different values, so there is still data to be read in the buffer.</div>
<div class="separator" style="clear: both; text-align: left;">
Obviously while you read and write you increment the relevant pointer, resetting it to zero when it reaches the end of the buffer.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This is one way to manage asynchronous communications, of course you could add some logic in your Interrupt handler routine to make your application react immediately i.e. when a specific character is received.</div>
<div class="separator" style="clear: both; text-align: left;">
It is in genreral good practice, tho, to have as little logic as possible in the ISR routines, they should complete in the shortest amount of time possible.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now, the funny thing is that the buffer we described is also called a FIFO (First In-First Out) buffer... which is already supported via hardware in the Cortex M3.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
That's right, if you needed just a few bytes in your buffer, no need to set up an ISR, you could simply enable the internal FIFO and you can still do it even if you decide to use interrupts.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">void SER_fifo(int uart,uint32_t enable,uint32_t dma,uint32_t trigger)</span></div>
<div class="separator" style="clear: both;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span></div>
<div class="separator" style="clear: both;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>LPC_UART_TypeDef *pUart;</span></div>
<div class="separator" style="clear: both;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>pUart = __get_uart_base(uart);</span></div>
<div class="separator" style="clear: both;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>pUart->FCR |= (enable&0x1)|((dma&1)<<3)|((trigger&0x3)<<6);</span></div>
<div class="separator" style="clear: both;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span></div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
The Fifo Control Register (FCR) can be used to enable the Fifo, define how many bytes should be received by it before triggering an IRQ and if it should use a dma channel to automatically copy the data to a specific memory location.</div>
<div class="separator" style="clear: both;">
Neat eh?</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiM3J6ecpyHYot1zQFQ9izTqHNsOclSFTvL-pTM-tt6u-8OmhQAsjr4QQNYJ0lE4wlQH4GQ4rpmW265-XuA8Touk77UYjUjA6BnmoW3BFLpYHIEiMwFZaulNWae2_FZbaFB8J9MzznDWC4/s1600/FCR.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="433" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiM3J6ecpyHYot1zQFQ9izTqHNsOclSFTvL-pTM-tt6u-8OmhQAsjr4QQNYJ0lE4wlQH4GQ4rpmW265-XuA8Touk77UYjUjA6BnmoW3BFLpYHIEiMwFZaulNWae2_FZbaFB8J9MzznDWC4/s640/FCR.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
@NXP</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
You can also reset the fifos (both the output fifo and the input fifo)... wait.. output fifo?</div>
<div class="separator" style="clear: both;">
Yes, serial communication might be a bit slow for MCUs and imagine you need to send a few bytes out: the output fifo will be happy to store some of those bytes for you so you can go have fun doing other interesting tasks while it handles the communication.</div>
<div class="separator" style="clear: both;">
You can do the same thing with an ISR routine or even use both at the same time.</div>
<div class="separator" style="clear: both;">
Notice that you can activate both (RX and TX) fifos or none of them, but you cannot activate just RX and not TX or the other way round.</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Now, let's see the interrupts.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-59Q-Kgzdcvk_9UM37e5_SPs_xq5yfkmhkWWrdICFtpNx7YtS8IzBKN9woQbJN_gszWymQlG3bdFYnkE0Ha3X-Z0Vyxay7haMCO_laNevxip2xSz5IZWu-oiDyig7b44ZKbixCqys4K4/s1600/ier.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="374" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-59Q-Kgzdcvk_9UM37e5_SPs_xq5yfkmhkWWrdICFtpNx7YtS8IzBKN9woQbJN_gszWymQlG3bdFYnkE0Ha3X-Z0Vyxay7haMCO_laNevxip2xSz5IZWu-oiDyig7b44ZKbixCqys4K4/s640/ier.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The UARTxIER are the Interrupt Enable Registers for the various UARTS.</div>
There are two interrupts we want to consider there :<br />
- The one generated when a new byte is received (or when the number of bytes in the fifo reaches the trigger threshold, if enabled) and this is the RBR one.<br />
- The other, generated when the line is ready to send out some new data, meet the THRE (Transmit Hold Register Empty) interrupt.<br />
The third one is triggered when the status of the receive line changes.<br />
<br />
#define IER_RBR 0x01<br />
#define IER_THRE 0x02<br />
#define IER_RXLS 0x04<br />
pUart->IER = IER_RBR | IER_THRE | IER_RXLS; <br />
<br />
That line enables the uart interrupts... almost.<br />
Actually we also need to enable the Uartx IRQ in the Nested Vector Interrupt Controller (NVIC) which has a cool name because it does cool stuff.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">switch (uart)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 0: NVIC_EnableIRQ(UART0_IRQn); break;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 2: NVIC_EnableIRQ(UART2_IRQn); break;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 3: NVIC_EnableIRQ(UART3_IRQn); break;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<br />
Now interrupts will be fired upon events and we should really do something with them.<br />
To capture them we just need to define a function (one per each uart we use) with a specific name, I am using uart2 so :<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">void UART2_IRQHandler(void) __irq</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ...</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<br />
Now we need to fill it with some good code, because I never had luck in succesfully compiling a statement like "...", so I guess it's not going to work for you either.<br />
<br />
First thing, let's just say we want to have an input buffer which will be filled by the IRQHandler procedure.<br />
<br />
#define UART_RX_BUFSIZE 32<br />
uint8_t UART_RxBuf[UART_RX_BUFSIZE];<br />
uint8_t bufWptr =0;<br />
uint8_t bufRptr = 0;<br />
<br />
Then we need to consider that the IRQHandler will be called for every kind of uart (uart2 in my case) related interrupt.<br />
By "every" we actually mean as many as you can count with two fingers (or two bits), in other words : four.<br />
<br />
This is the Interrupt Identification Register (IIR) which can be used to get the IntID, a 2 bit number that identifies which interrupt we are dealing with.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEP5vupj51DqBa-CXAmcZ84eSiwicmaZadSM8m3-SD4dI-dd7v1PZK8FpFTnZzL33Jg8yK4iUvHW5orQw0KbOgBHnMkVyoXJTZ2yaxYdNNwyH-d1FfSWlL2qIZJ4yc4Do5ytPDp3_q6GI/s1600/IIR.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEP5vupj51DqBa-CXAmcZ84eSiwicmaZadSM8m3-SD4dI-dd7v1PZK8FpFTnZzL33Jg8yK4iUvHW5orQw0KbOgBHnMkVyoXJTZ2yaxYdNNwyH-d1FfSWlL2qIZJ4yc4Do5ytPDp3_q6GI/s400/IIR.png" width="400" /></a></div>
<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">void UART2_IRQHandler(void) __irq</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>uint8_t intId;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>intId = ((LPC_UART2->IIR)>>1)& 0x7;</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>switch (intId)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> case INTID_RXLS : break;</span><span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;">// whatever</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> case INTID_RDA : </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> while((LPC_UART2->LSR) & 0x1) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> UART_RxBuf[bufWptr++] = LPC_UART2->RBR;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> if (bufWptr >= UART_RX_BUFSIZE)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> bufWptr = 0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> break;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> case INTID_CTI : break; // whatever</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> case INTID_THRE : break; // whatever</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<br />
This is a simple implementation that should provide RX interrupt handling, notice it does not check if our software buffer is overran.<br />
<br />
Let's just add a couple of functions to get the data out of the buffer and check if we should do it.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">int SER_hasBufData()</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return (bufWptr!=bufRptr);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">uint8_t SER_getBufData()</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> if (bufRptr>=UART_RX_BUFSIZE) bufRptr=0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return UART_RxBuf[bufRptr++];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<br />
And finally we can update the test program<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">int main(void)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> SystemInit();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> setpll0(25,2,3);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> SystemCoreClockUpdate();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> SER_init(2,115200);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> SER_fifo(2,1,0,0);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> while (1) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> delay(10000000);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> SER_putString (2, ".");</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> while (SER_hasBufData())</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> {<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>SER_putString (2, "Received : ");</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>SER_putChar(2,SER_getBufData());</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>SER_putString (2, "\r\n");</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> } </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return 0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<br />
As usual, you can get my full code <a href="https://dl.dropboxusercontent.com/u/7091137/cortexm3/uart2_irq.zip" target="_blank">here</a>.Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-84474069973599180392015-05-17T21:32:00.002+02:002015-05-19T11:05:32.375+02:00Cortex M3 - UART / 1Hello again, been a bit too busy to blog for quite some time, sorry for that.<br />
<br />
I have a nice Cortex M3 board around since some time, it is based on a NXP LPC1768, which is quite a neat processor.<br />
It can run up to 100MHz, has 512K Flash, 64K Sram and a nice set of peripherals.<br />
<br />
The board itself is quite nice too, not sure you can still find it around -ebay listings below, to give you an idea on what's available-, mine is called "LandTiger" and I guess it is just some clone of some popular dev board.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhqHnKQmcjchESEatZy5WSBi38Ne_8V_SjeTaMSjlNfJWJEbghvG44C4hGEWDtKVP5RVVzv-aoVc_FomvPLwATF2SUSuBRhlz6XY8ryio8LKxEZuGBFgwFsRslJoEA2C7Q8cZ30W2fjJk/s1600/lt.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="247" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhqHnKQmcjchESEatZy5WSBi38Ne_8V_SjeTaMSjlNfJWJEbghvG44C4hGEWDtKVP5RVVzv-aoVc_FomvPLwATF2SUSuBRhlz6XY8ryio8LKxEZuGBFgwFsRslJoEA2C7Q8cZ30W2fjJk/s400/lt.png" width="400" /></a></div>
<br />
<br />
<script type="text/javascript" src='http://adn.ebay.com/files/js/min/jquery-1.6.2-min.js'></script>
<script type="text/javascript" src='http://adn.ebay.com/files/js/min/ebay_activeContent-min.js'></script>
<script charset="utf-8" type="text/javascript">
document.write('\x3Cscript type="text/javascript" charset="utf-8" src="http://adn.ebay.com/cb?programId=1&campId=5337103411&toolId=10026&keyword=LPC1768&width=728&height=90&font=1&textColor=000000&linkColor=424242&arrowColor=FF6600&color1=FF9900&color2=[COLORTWO]&format=ImageLink&contentType=TEXT_AND_IMAGE&enableSearch=y&usePopularSearches=n&freeShipping=n&topRatedSeller=n&itemsWithPayPal=n&descriptionSearch=y&showKwCatLink=n&excludeCatId=&excludeKeyword=&catId=&disWithin=200&ctx=n&autoscroll=n&flashEnabled=' + isFlashEnabled + '&pageTitle=' + _epn__pageTitle + '&cachebuster=' + (Math.floor(Math.random() * 10000000 )) + '">\x3C/script>' );
</script>
<br />
That said, I wanted to play with the UART using a standard CMSIS approach.<br />
CMSIS stands for Cortex Microcontroller Software Intertface Standard, it is <a href="http://www.arm.com/products/processors/cortex-m/cortex-microcontroller-software-interface-standard.php" target="_blank">defined by ARM</a> and supported by various IDEs.<br />
<br />
CMSIS deserves a post on its own, if you don't know it, there is quite a lot of info around already, but I might post myself a sort of "CMSIS for dummies" some time.<br />
<br />
Regarding the IDE/toolchain there are quite a few options, currently I am using Keil uVision5 (there is a free version, codesize limited), but I also tried IAR and CoIDE (which is open source).<br />
They all work, and all of them require a bit of fight to get the things the way you want them (at least this happened to me), I couldn't really pick a winner in the end, but decided to stick to Keil uVision.<br />
<br />
So, the UART.<br />
Why the UART first of all?<br />
Meh, getting serial communication is pretty key to allow some remote debugging, so it is a good place to start (maybe just after blinking a few LEDs).<br />
<br />
Now, CMSIS provides a layer that gives some kind of standard helping you when you have to port your code from a device to another.<br />
For what I can see, you cannot simply change device, recompile and hope everything works.<br />
NXP devices have some peculairities and need to be handled differently from STM devices etc.<br />
<br />
The way you normally manage this is to generate your own abstraction layer (or use some available libraries that do just that).<br />
<br />
This post is about the LPC1768, but most of the info might eventually apply to other devices too, provided the register addresses will be different, but those are defined in a CMSIS include file usually provided by the vendor.<br />
<br />
So, the LPC1768 has 4 UARTs and uarts 0,2 and 3 work pretty much the same way.<br />
Uart1 is a bit special, so it will not be discussed here.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4aQvaxxMA-i7MDU7BBQLi_C3sQICKRt24v7STbFdS1TR8XJ0Aq6kGHN3LbLXZq-S1Wl6oBytFpIjfqGwLwPqS-jtJUPq5UXcpptH78HGmOT2u9VNeyNDnD_jco2u32-n6EfYNK9SDTEc/s1600/uart_regs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4aQvaxxMA-i7MDU7BBQLi_C3sQICKRt24v7STbFdS1TR8XJ0Aq6kGHN3LbLXZq-S1Wl6oBytFpIjfqGwLwPqS-jtJUPq5UXcpptH78HGmOT2u9VNeyNDnD_jco2u32-n6EfYNK9SDTEc/s640/uart_regs.png" width="572" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"><i>(@NXP)</i></span></div>
<br />
There are quite a few registers to play with, as you can see from the LPC17xx manual.<br />
Two easy ones : Receive Register (<b>RBR</b>) and Transmit Register (<b>THR</b>), these should not require a lot of explanations.<br />
Can you see the specification (DLAB=0)?<br />
That means that the Divisor LAtch Bit must be set to zero.<br />
We use the <b>DLAB</b> to set the frequency divider (hence the name) to obtain specific baud rates, basically when you set the baud rates, the DLAB bit must be 1, in any other moment it has to be 0 (and in some case it does not matter, but leave it to zero in that case :) ).<br />
The divisor is set via the <b>DLL</b> and <b>DLM</b> registers, containing the low 8 bits and the high 8 bits of a 16 bit unsigned integer, being the divisor.<br />
<br />
DLAB is the bit 7 of the <b>LCR </b>register.<br />
<br />
But setting the baud rates and the typical 8,N,1 configuration is no all you have to do.<br />
<br />
First of all, Cortex Microcontrollers are usually designed with power saving objectives in mind, so it is often the case that by default peripherals are turned OFF.<br />
Before you can configure the UART, it is a good idea to turn it on!<br />
<br />
This is quite easy, it is done via the <b>P</b>ower <b>CON</b>trol for <b>P</b>eripherals (<b>PCONP</b>) register<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxJ2syYvC4bC8S0z6DsbgjXN9HSmLPB34CvhqsxjPa-2L3Iqrb-tHGNJX7wAxednsKefmp7tXAepeOqW9tZYOvhkCEzGilAzkPcCFDZMdiGqIOzp-O6dK6WoiaYVFEeLm4DxMGIjb7Tgo/s1600/pconp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxJ2syYvC4bC8S0z6DsbgjXN9HSmLPB34CvhqsxjPa-2L3Iqrb-tHGNJX7wAxednsKefmp7tXAepeOqW9tZYOvhkCEzGilAzkPcCFDZMdiGqIOzp-O6dK6WoiaYVFEeLm4DxMGIjb7Tgo/s640/pconp.png" width="554" /></a></div>
<i style="font-size: small; text-align: center;">(@NXP)</i><br />
<i style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span></i>
<span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><b>LPC_UART_TypeDef * __get_uart_base(int uart)</b></span></span><br />
<span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><b>{</b></span></span><br />
<span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">switch (uart)</span></span><br />
<span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span></span><br />
<span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 0: </span></span><span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SC->PCONP |= (1<<3); </span></span><span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">break;</span></span><br />
<span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 2: </span></span><span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SC->PCONP |= (1<<24); </span></span><span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">break;</span></span><span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><br />
<span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 3: </span></span><span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_SC->PCONP |= (1<<25); </span></span><span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">break;</span></span><span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><br />
<span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span></span><br />
<span style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><b>}</b></span></span><br />
<br />
If you check the simple code and the register, you will notice that depending on which uart we want to use, we turn on one single bit of the register (3, 24 or 25).<br />
<br />
So, now the UART is on, but there is another typical feature of cortex microcontrollers : pins are used for different purposes, so there is a multiplexer that has to be configured to make sure we have a RX and a TX pin connected to our uart.<br />
<br />
This is done via the PINSELx registers, for the uarts we will need PINSEL0 (uart0 and 2) and PINSEL1 (uart3).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjApJaUa-EfwPVXMoeRMv77fVpNJiH6P76cML5Q7sM41nRguSrDf1LGuVM-N1JNSNp07pgtbIkJQEcDAvlw_ssTw-csFDtA3jXAhIjXkAgCojomPAfz7XWI0FKaJYKNDO8NwKKECE93K_Q/s1600/pinsel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjApJaUa-EfwPVXMoeRMv77fVpNJiH6P76cML5Q7sM41nRguSrDf1LGuVM-N1JNSNp07pgtbIkJQEcDAvlw_ssTw-csFDtA3jXAhIjXkAgCojomPAfz7XWI0FKaJYKNDO8NwKKECE93K_Q/s640/pinsel.png" width="426" /></a></div>
<br />
Next comes the peripheral (uartx) clock configuration.<br />
Cortex M3 MCUs can use different clock signals per each peripheral, the LPC1768 allows to divide the system clock by 1,2,4 or 8 times.<br />
<br />
These dividers are configured using two bits per each peripheral in the PCLKSELx registers<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5v0dHZCp53GGrXKebZPpyxG2UjpdGbKGdx60bMPm_H9VXr6vmUQLe4MeyZsh7CvAPu9_2_CqUzYchTUmXMF79Nvoe-JfMGzkr8PC_LNlUBF-h-OQYt5tamcrYMy4cqhiyhYFP-2AzSNQ/s1600/pclk1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="478" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5v0dHZCp53GGrXKebZPpyxG2UjpdGbKGdx60bMPm_H9VXr6vmUQLe4MeyZsh7CvAPu9_2_CqUzYchTUmXMF79Nvoe-JfMGzkr8PC_LNlUBF-h-OQYt5tamcrYMy4cqhiyhYFP-2AzSNQ/s640/pclk1.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4q3RribsspQmyoOsifDfmhCgWMFENzWr3N7uwMRebSJo9cP1k_oqUdpwnCCDDwFrwkg50dMsMxsw645qi8VVLJr-g32X1ap4-bnS-63sC2UYRToSZFvb3wDkj3Y1lJ76bJ-fnPbPffoo/s1600/pclk2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4q3RribsspQmyoOsifDfmhCgWMFENzWr3N7uwMRebSJo9cP1k_oqUdpwnCCDDwFrwkg50dMsMxsw645qi8VVLJr-g32X1ap4-bnS-63sC2UYRToSZFvb3wDkj3Y1lJ76bJ-fnPbPffoo/s640/pclk2.png" width="622" /></a></div>
<br />
If we need to have reliable communication at high baud rates, it is advisable to set the value to 0x01, equal to no clock division.<br />
<br />
We can expand the previous switch to include both pin and clock configuration and embed everything in a SER_On(int uart) function<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">void SER_On(int uart)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<i style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">switch (uart)</span></i><br />
<i style="text-align: center;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span></i><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 0: </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>LPC_PINCON->PINSEL0 &= (0x0F<<4); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_PINCON->PINSEL0 |= (1 << 4); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">/* Pin P0.2 used as TXD0 (Com0) */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_PINCON->PINSEL0 |= (1 << 6); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">/* Pin P0.3 used as RXD0 (Com0) */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_SC->PCONP |= (1<<3); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_SC->PCLKSEL0 &= ~(3<<6);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>LPC_SC->PCLKSEL0 |= (1<<6); // = CCLK</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"> break;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 2:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>LPC_PINCON->PINSEL0 &= (0x0F<<20); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_PINCON->PINSEL0 |= (1 << 20); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">/* Pin P0.10 used as TXD2 (Com2) */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_PINCON->PINSEL0 |= (1 << 22); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">/* Pin P0.11 used as RXD2 (Com2) */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>LPC_SC->PCONP |=(1<<24);<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_SC->PCLKSEL1 &= ~(3<<16);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>LPC_SC->PCLKSEL1 |= (1<<16); // = CCLK</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"> break;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 3:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>LPC_PINCON->PINSEL1 &= (0x0F<<18); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_PINCON->PINSEL1 |= (3 << 18); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">/* Pin P0.25 used as TXD3 (Com3) */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_PINCON->PINSEL1 |= (3 << 20); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">/* Pin P0.26 used as RXD3 (Com3) */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>LPC_SC->PCONP |=(1<<25);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_SC->PCLKSEL1 &= ~(3<<18);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>LPC_SC->PCLKSEL1 |= (1<<18); // = CCLK<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"> break;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><b>}</b></span><br />
<br />
We can now configure the UARTs, but it is good to define a handy function that returns the uart base address to access the registers, so that each time we don't need to do stuff like "if (uart==0) then ... " etc.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">LPC_UART_TypeDef * __get_uart_base(int uart)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> switch (uart)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 0:</span> <span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;">return LPC_UART0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 2: </span><span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;">return LPC_UART2;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> case 3:</span><span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"> return LPC_UART3;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return LPC_UART0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<br />
the LPC_UART_TypeDef structure and the LPC_UARTx constants are provided in the LPC17xx.h CMSIS include file, other vendors (non NXP) will use different names, but should not be difficult to find the matching structures and constants.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">void SER_init (int uart,int baudrate) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_UART_TypeDef *pUart;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> uint32_t fdiv;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> pUart = __get_uart_base(uart);</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> SER_On(uart);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> // set to 8 databits, no parity, and 1 stop bit</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> pUart->LCR = 0x83; //DLAB on</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> // do baudrate calculation</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> fdiv = (SystemCoreClock / 16) / baudrate; </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> pUart->DLM = (fdiv >> 8) & 0xFF;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> pUart->DLL = (fdiv) & 0xFF;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> pUart->LCR = 0x3;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> pUart->FCR = 0x6;<span class="Apple-tab-span" style="white-space: pre;"> </span>//reset read and write fifo</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<br />
First we get the base address with the __get_uart_base(uart) function we defined at the beginning.<br />
Then we turn the UART on, select the clock and configure the pins with the SER_On function.<br />
<br />
At this point we are ready to configure the baud rate divider and we know that for this one the DLAB must be on, turns out the DLAB is bit 7 ot the Line Control Register (<b>LCR</b>), the 3 in the lower part of the register sets the 8,N,1 part.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpLiWUVMddbelJcfoA2JBsuZ9oQvzOzvf8MTKsbtzwZGp9J3jUz2T_QfLuCnVLAFwz4MKaEIz14WdCzgimgrPxdZOT1m4bvkWsEdSZVs-G5bM0QSCECnp_ID37osbhRfT9H4s37y26CTM/s1600/lcr.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="436" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpLiWUVMddbelJcfoA2JBsuZ9oQvzOzvf8MTKsbtzwZGp9J3jUz2T_QfLuCnVLAFwz4MKaEIz14WdCzgimgrPxdZOT1m4bvkWsEdSZVs-G5bM0QSCECnp_ID37osbhRfT9H4s37y26CTM/s640/lcr.png" width="640" /></a></div>
<br />
Now we need to calculate the fdiv divider.<br />
There is a formula for that one:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;">fdiv = (SystemCoreClock / 16) / baudrate; </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: inherit;">However, trap for young players -it tricked me initially- this formula assumes that your uart pclk divider is 1 (!!).</span><br />
<span style="font-family: inherit;">If you set pclk, say to /4 , then also the divider will have to be divided by 4.</span><br />
<span style="font-family: inherit;">fdiv is then copied into DLM and DLL (high part and low part), finally the DLAB is turned off again.</span><br />
<span style="font-family: inherit;"><br /></span>
<i><span style="font-family: inherit;">Note : <b>SystemCoreClock </b>is a variable provided by the CMSIS core modules, if you decide to set manually in your code the cpu clock, then you should also call </span> <b>SystemCoreClockUpdate()</b>; right after to ensure that the variable SystemCoreClock is properly updated.</i> <span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">The final line resets both the TX and RX fifos and disables them via the Fifo Control Register (<b>FCR</b>).</span><br />
<br />
<span style="font-family: inherit;">Ok, so, now we are all set to send out some data, we need a putchar function:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">int SER_putChar (int uart, int c) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_UART_TypeDef *pUart;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> pUart = __get_uart_base(uart);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> while (!(pUart->LSR & SER_THRE));</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return (pUart->THR = c);</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Writing a char to the uart is as simple as putting it in the Transmit Hold Register (THR)... well, <u>almost</u> that simple, we just need to wait the uart is redy to send out a new character and we do that by polling the Line Status Register (<b>LSR</b>) </span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjai29VnHkZr7IpvjsLFznK2g7Cn-eel48j7tG_uoMBIaCXS3RG7hhFOLTC0vHDYVbH7AzccO9xN5oYhGVfVX7C1hS__EoSNz-MRDfRR7ONouhuj6fHOyXlQgy8lkL_XFcRO0-TH8_G6QI/s1600/lsr.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjai29VnHkZr7IpvjsLFznK2g7Cn-eel48j7tG_uoMBIaCXS3RG7hhFOLTC0vHDYVbH7AzccO9xN5oYhGVfVX7C1hS__EoSNz-MRDfRR7ONouhuj6fHOyXlQgy8lkL_XFcRO0-TH8_G6QI/s640/lsr.png" width="514" /></a></div>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">I defined a few constants to map to the register bits:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#define SER_RDR 0x1</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#define SER_OE 0x2</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#define SER_PER 0x4</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#define SER_FE 0x8</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#define SER_BI 0x10</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#define SER_THRE 0x20</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#define SER_TEMT 0x40</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">If you check bit 5, you notice that it tells us if the THR is empty and ready to receive another byte.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Using the same register we can discover if we have incoming data</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">int SER_hasData(int uart)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_UART_TypeDef *pUart;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> pUart = __get_uart_base(uart);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return pUart->LSR & SER_RDR;</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">and then we can read from RX (register <b>RBR</b>)</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">int SER_getChar (int uart) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> LPC_UART_TypeDef *pUart;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"> pUart = __get_uart_base(uart);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> while (!(pUart->LSR & SER_RDR));</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return (pUart->RBR);</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">and handle output strings as well</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">void SER_putString (int uart, unsigned char *s) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> while (*s != 0) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> SER_putChar(uart, *s++);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Ok, now a simple test program:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#include "lpc17xx.h"</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">void delay(uint32_t count)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> while (count>0) count--;</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<div>
<br /></div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">int main(void)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>SystemInit(); //CMSIS standard</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>SER_init(2,115200);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> while (1) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> delay(10000000); // I am running @100MHz</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> SER_putString (2, ".");</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> while (SER_hasData(2))</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> {<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> <span class="Apple-tab-span" style="white-space: pre;"> </span>SER_putString (2, "Received : ");</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> <span class="Apple-tab-span" style="white-space: pre;"> </span>SER_putChar(2,SER_getChar(2));</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>SER_putString (2, "\r\n");</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> } </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return 0;</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">}</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">This is really a basic program, but should give you a basic start to play with the uart.</span><br />
<span style="font-family: inherit;">So far we did not enable interrupts, but if you would like to play with my code, you can find it <a href="https://dl.dropboxusercontent.com/u/7091137/cortexm3/uart.zip" target="_blank">here</a>.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span>Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-83998885051147920862015-04-06T12:19:00.001+02:002015-04-06T14:24:48.481+02:00Stellaris Launchpad - NRF24L01 radio - Part 2<i>Ok, I had this one in draft for long enough now.</i><br />
<i>I still need to figure out a few things, so a part 3 will be needed in the future, also I initially had issues with Dynamic Payloads as I forgot to issue the FEATURE = EN_DPL command, hopefully shoudl work better now.</i><br />
<br />
<br />
In a <a href="http://fortytwoandnow.blogspot.ch/2014/04/strellaris-launchpad-nrf24l01-radio.html" target="_blank">previous post</a> we saw some basic concepts and functionality of the NRF24L01 chip.<br />
<br />
We managed to establish a SPI communication between the Stellaris and the module, but we did not perform any data transmission across two nodes.<br />
to achieve that we need to add a few functions to our library and decide some basic defaults for it.<br />
<br />
I think this automatic ACK system (if you don't know what I am talking about, you really need to read my previous post) is pretty cool and I think it would be fair to use it by default, so the library will assume we are going to use it, should we have any issues with it later on, we might eventually change approach.<br />
<br />
While supporting multiple RX pipes is indeed interesting, so I would rather keep that functionality in the library, we can assume that, by default, communication will be through pipe0.<br />
<br />
The function nrf_enablePipes accepts a byte (bits 0:5 represent the 6 pipes) does 3 things :<br />
<br />
1) Enables the selected pipes<br />
2) Activates the AUTO ACK magic for them<br />
3) configures them for dynamic payload<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void nrf_enablePipes(unsigned char pipes)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> nrf_writeReg(EN_AA, pipes); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> // enable AUTO ACK on pipes</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> nrf_writeReg(EN_RXADDR, pipes); // enable pipes</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> nrf_writeReg(</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> FEATURE, 1<<EN_DPL ); //enable DPL</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> nrf_writeReg(DYNPD, pipes); // dynamic payload for pipes</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<br />
About dynamic payload (DPL), the Datasheet says :<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpX6Mms6DfqfqPZ3toyxaV45e0s8GyWZCmV0pCLJMJZa4QOjPZhw4obehjwNNbqE60SmP2IhD93uSYrcp5ttyoyOns5KV10rXAS7yu6-BIu3kGkFdjqWyqLjgYo_TaXChpxzUNUnfQtmg/s1600/nrf02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpX6Mms6DfqfqPZ3toyxaV45e0s8GyWZCmV0pCLJMJZa4QOjPZhw4obehjwNNbqE60SmP2IhD93uSYrcp5ttyoyOns5KV10rXAS7yu6-BIu3kGkFdjqWyqLjgYo_TaXChpxzUNUnfQtmg/s1600/nrf02.jpg" height="241" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<i>(@Nordic)</i></div>
<br />
<br />
Another default I picked is to use 5 byte addressing.<br />
<br />
Now we need to be able to set the TX address and the various RX addresses for the RX pipes.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> /*</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#define RX_ADDR_P0 0x0A</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#define RX_ADDR_P1 0x0B</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#define RX_ADDR_P2 0x0C</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#define RX_ADDR_P3 0x0D</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#define RX_ADDR_P4 0x0E</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#define RX_ADDR_P5 0x0F</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">pipe : 0..5</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void nrf_setRXAddress(unsigned char pipe, unsigned char *addr)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> nrf_writeRegMulti(RX_ADDR_P0+pipe, addr, 5);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void nrf_setTXAddress(unsigned char *addr)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> nrf_writeRegMulti(TX_ADDR, addr, 5);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<br />
the writeRegMulti function works like the writeReg, but accepts a buffer and sends n bytes instead of a single one, we need it for setting the addresses since they are 5 bytes long.<br />
<br />
As we discussed in the previous post, a node can be set up as PRX or PTX, this is done setting the lowest bit in the CONFIG register : 1 means PRX, 0 means PTX.<br />
The same register is used to specifcy if a CRC is used, int hat case wether is it 1 or 2 byte long,m plus there are 3 bits used to mask the interrupts.<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: inherit;">You can find more info on the CONFIG register <a href="http://nrqm.pbworks.com/w/page/4416158/nRF24L01%20%E2%80%93%20CONFIG%20Register" target="_blank">here</a>.</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">/**</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * Set crc = 0 to disable crc, 1 for 1 byte ,2 for 2 bytes</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void nrf_config(unsigned char maskRXirq, </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> unsigned char maskTXirq,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> unsigned char maskMAXirq,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char crc,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> unsigned char pwUp,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> unsigned char prx)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> unsigned char val = maskRXirq<<6 | </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> maskTXirq<<5 | </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> maskMAXirq <<4;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if (crc>0) val |= 8; else crc--;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> val |= crc <<2 | pwUp<<1 | prx;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> nrf_writeReg(CONFIG,val);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<br />
When we need to initiate a transmission, we need to set up the node as PTX, to set the TX address to the address of the receiving module, plus the Pipe0 address equal to the TX one.<br />
<br />
Additionally we might want to configure the number of transmission attempts (if Auto ACK fails) and the delay between them<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">/**</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * delay : 0 = 250us, 1=500us ... 15=4000us</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> * count : 0..15 auto retransmit if AA fails</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> */</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void nrf_setRetransmit(unsigned char count, </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> unsigned char rDelay)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> unsigned char val = ((rDelay&0x0f)<<4) | (count&0x0f);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> nrf_writeReg(SETUP_RETR,val);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<div>
<br /></div>
<div>
In our experiment we will use node 1 with address "node1" (in ASCII) and node 2 with address "node2" and we will try to have them communicate @2MBps on the channel 0x10.</div>
<div>
Node 1 will try to send a payload containing the data "TEST1234" every 2 seconds and we will use the RGB leds on the two Launchpads to provide some feedback.</div>
<div>
<br />
For this initial test we will do something simple, however I believe we still need to use two pipes.<br />
The reason for this is that when the PTX sends data, it has to configure the RX pipe0 with the same address of the receiver, therefore it needs to be able to listen on a different pipe, with a unique address, in order to be contacted when it switches back to PRX.</div>
<div>
<br />
Initially I was thinking to have one of the two nodes running on Arduino, to use a know library such as Mirf to minimize the debug, unfortunately I am not really sure if Mirf allows to be configured properly and if that is the case, I don't know how, while with my library at least I know all the settings.<br />
<br />
<i>Ok, I stopped here because I got lost with the DPL feature, as stated at the beginning, should work now, need to experiment a bit more (been doing other stuff for quite some time) and then hopefully a final Part 3 will be posted :)</i> </div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-7998713058563875902015-01-15T19:01:00.001+01:002015-01-15T22:26:03.672+01:00Unpacking my new TelescopeI recently bought a SkyWatcher Maksutov-Cassegrain 150 Pro, with a HEQ5 Pro mount.<br />
<div>
<br /></div>
<div>
I am quite a newbie with this kind of stuff, so I cannot yet review thre equipment, but I can give you my first impressions.</div>
<div>
<br /></div>
<div>
Normally I write about micro-electronics, so this post is a bit "different", still my blog is about geekiness and well, a telescope qualifies in the category :)</div>
<div>
<br /></div>
<div>
The purpose of this post is to show you what you get should you buy the same equipment and also to provide a detailed step-by-step setup guide, since the manual is quite basic on that part.</div>
<div>
<br /></div>
<div>
Anyhow, it's not completely true that microelectronics is not involved... in fact the mount (uses 2 stepper motors) has a serial protocol which the vendor released in open source (twink! twink!).</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_z7iuJEr6NUAGUYT4y-cgDlCZEb9nlE_B6BZs6U9L7mMGrMjvHG-RQwke2-PZ6jcmALDpp8NHnjzvE92UVkNXkfozO9sDnCMoumSPRK67qz6QTNCuDpUPPwkty5pStnVderkF-7JsW0c/s1600/1-boxes.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_z7iuJEr6NUAGUYT4y-cgDlCZEb9nlE_B6BZs6U9L7mMGrMjvHG-RQwke2-PZ6jcmALDpp8NHnjzvE92UVkNXkfozO9sDnCMoumSPRK67qz6QTNCuDpUPPwkty5pStnVderkF-7JsW0c/s1600/1-boxes.JPG" height="266" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
These are the boxes : 1) tripod with counter-weights, 2) the tube and 3) the mount.<br />
It is always a good idea to make some room before unpacking stuff.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAnMxNWbRJlJWVNzDxLKbrGiYyr4QXZqSPC_iMWrLcbEI7LkYCbBctYqC2EM6rkYvQHoYjoD4xFaRqzRUHHuY0rDS5IF15mFd0k0IaHEcOVNdWL2uujLi9wLDC8orq7NU-IhDJT8_kFCg/s1600/2-tube.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAnMxNWbRJlJWVNzDxLKbrGiYyr4QXZqSPC_iMWrLcbEI7LkYCbBctYqC2EM6rkYvQHoYjoD4xFaRqzRUHHuY0rDS5IF15mFd0k0IaHEcOVNdWL2uujLi9wLDC8orq7NU-IhDJT8_kFCg/s1600/2-tube.JPG" height="400" width="266" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
The tube itself comes with a nice package to protect it during shipping, better save these protections for future use.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUBkH5795rD-7szyP7YXpihEn_-fbEB9TLRbO3c3WmGwXx1gvuCu0tj97UCmdF3R1b6tmt7Ou5rIgB7stYqcBhS2r_rMpu9Jzs95QHbAkNQbNZmbvnUyJhqtRT4nGoZl5Tc1U-1G2IMY4/s1600/3-content.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUBkH5795rD-7szyP7YXpihEn_-fbEB9TLRbO3c3WmGwXx1gvuCu0tj97UCmdF3R1b6tmt7Ou5rIgB7stYqcBhS2r_rMpu9Jzs95QHbAkNQbNZmbvnUyJhqtRT4nGoZl5Tc1U-1G2IMY4/s1600/3-content.JPG" height="640" width="426" /></a></div>
<br />
Finally, this is all the equipment which I will describe starting from the top left :<br />
1) Manuals, marketing stuff etc in all the first row. Nothing fancy here<br />
2) Two counter-weights (yes, they are HEAVY), the eyepiece /other stuff holder which is part of the tripod, a box which contained the eyepiece and some other spare parts<br />
3) The tripod<br />
4) Tube (telescope), finder scope, diagonal and eyepiece<br />
5) the mount, goto controller handler, car cigarette power cable, 2 allen wrenches, locking screws, spare mount sled, serial cables, goto controller<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzp_qpeTYVhY7jMM-oqHMCCgnTAYke9c-eXIsd9OMn2F6ao34JugA2MQFPrK51phZPDDCFcaulD76IE7IolgD5sFjfGp065-ZV_yqt_nzZICYeYA0jwK6FnoUihy00Z_ClLZINb9Pivd4/s1600/4-tripod.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzp_qpeTYVhY7jMM-oqHMCCgnTAYke9c-eXIsd9OMn2F6ao34JugA2MQFPrK51phZPDDCFcaulD76IE7IolgD5sFjfGp065-ZV_yqt_nzZICYeYA0jwK6FnoUihy00Z_ClLZINb9Pivd4/s1600/4-tripod.JPG" height="400" width="266" /></a></div>
<br />
First step : open up the tripod.<br />
Looks like a stable and sturdy tripod, make sure you open it completely, I did not extend the legs for now.<br />
Notice the tripod is not symmetric, one side is labeled "N" and it should be oriented to north.<br />
On that side there is a metal tab used to lock the azimuth rotation of the mount in respect to the tripod.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVrPjnoQ5GUicA276gD6lB4axFn4VBhyphenhyphenGqs-4bUg0b05eJHm2Ff8hpCthQFd_VkpTlvM_cumWhwgVk5G66A1iWUpEq1VL1XNa08nSQl5QXU6qtk5na_lk2rfuUte15Smqu9BsNHPiJZxA/s1600/5-mount.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVrPjnoQ5GUicA276gD6lB4axFn4VBhyphenhyphenGqs-4bUg0b05eJHm2Ff8hpCthQFd_VkpTlvM_cumWhwgVk5G66A1iWUpEq1VL1XNa08nSQl5QXU6qtk5na_lk2rfuUte15Smqu9BsNHPiJZxA/s1600/5-mount.JPG" height="400" width="266" /></a></div>
<br />
The mount comes next, notice the two screws that will be pressing on the previously described tab.<br />
Make sure you undo them properly before placing the mount on the tripod.<br />
Once done start screwing in the bottom rod.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFxlU9kqxw3eCIClFPUcx6Veb8zuNvLH0L6f0sdeRuMNyFu9OJNZFWGmpm7wjgPk1q6IVKxE5qHxztismulvvXZc151jmf2JRPCgMflO5IOcG04NcLlVCTXnxMzx17wrgywoTxHeqbhaQ/s1600/6-holder.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFxlU9kqxw3eCIClFPUcx6Veb8zuNvLH0L6f0sdeRuMNyFu9OJNZFWGmpm7wjgPk1q6IVKxE5qHxztismulvvXZc151jmf2JRPCgMflO5IOcG04NcLlVCTXnxMzx17wrgywoTxHeqbhaQ/s1600/6-holder.JPG" height="400" width="266" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
With the mount in place, we want to stabilize the tripod : unscrew the bottom part of the threaded rod, place the eyepiece / stuff holder and then screw back in the bottom part.<br />
Notice that there are 3 small extensions that are supposed to press against the tripod legs and prevent them from folding back.<br />
Also notice there is a U slot in the holder, this will be used to rest the go-to controller, so face it in the direction where you like to have the controller.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkRQtVJ2CxOiACBZ0Z_AcKHFfJMzwGZCpQtyRjFlyacU9aVlQayh99fBb2ObRR1i58l6BvbN2gp2vWAYp-Gie88f7K5pF-C13qEBCE8j-sPi-N_WkBSr5MJt7PVTvNfbH6yLDpxdAWScI/s1600/7-counterweights.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkRQtVJ2CxOiACBZ0Z_AcKHFfJMzwGZCpQtyRjFlyacU9aVlQayh99fBb2ObRR1i58l6BvbN2gp2vWAYp-Gie88f7K5pF-C13qEBCE8j-sPi-N_WkBSr5MJt7PVTvNfbH6yLDpxdAWScI/s1600/7-counterweights.JPG" height="400" width="266" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
Counterweigths: Unlock the clouch that controls the coutnerweight bar so that it extends completely, then lock it again.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
Remove the safety screw at the end of the bar and slide in the weights, one at a time, lock the one you inserted first before adding the second, finally put back the safety screw.<br />
At this point it is probably a good idea to have the counterweghts a bit "low", at least like the position you see in the pciture.<br />
This will help for the next steps as it will ensure that the scope will stay up once we install it and it will not start spinning around.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgaAOxHS7V2wHy5zrn22nvgkBOLTuBW_yPffoB-3YeT2_qFQ3P5RnuVJPJQzmQFnuisGGm0wF_db90Jahpvyi2I4Jdxa6-Y5rwn4hKM8m7tsQcBF-r1Q9mYxOIZ-I8yQ-kTSt8VCAm15E/s1600/8-test-tube.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgaAOxHS7V2wHy5zrn22nvgkBOLTuBW_yPffoB-3YeT2_qFQ3P5RnuVJPJQzmQFnuisGGm0wF_db90Jahpvyi2I4Jdxa6-Y5rwn4hKM8m7tsQcBF-r1Q9mYxOIZ-I8yQ-kTSt8VCAm15E/s1600/8-test-tube.JPG" height="400" width="266" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
You don't need to install the additional sled, I just placed it there to check how the locking mechanism works and to ensure there were no particular details I had to take care of when placing the scope.<br />
This picture shows how your scope is going to be attached to the mount.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4fahG9UZ-fPtttHeeam6sZ2TMee1mq7ifb-Wf1cR1RLKwwgpk4x2V6YEprEr8RwUGJVBkQPvevITm8_zPyXNaki6O5l3kUL_qi514P2Grc70hJ4zX6hw_A64GoZ41_y2vPEv7AnrJ68I/s1600/10-lock.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4fahG9UZ-fPtttHeeam6sZ2TMee1mq7ifb-Wf1cR1RLKwwgpk4x2V6YEprEr8RwUGJVBkQPvevITm8_zPyXNaki6O5l3kUL_qi514P2Grc70hJ4zX6hw_A64GoZ41_y2vPEv7AnrJ68I/s1600/10-lock.JPG" height="266" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
One final thing before installing the scope : screw in the two small threaded rods, they are placed on the two opposite sides of the mount.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSSEGft48a-ow2P4JwxE7HgsBzech8V2nnVRgsHNXc0aeezoSGoa-uLCb6M7MXlmW_gOQppo8zOK1gb9-4jyvFeRMLwq3zUTKpK1U6yK_lZJnhvVJL5RGPLZatV1ME4bGddq8E6O339ZU/s1600/11-tube-on.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSSEGft48a-ow2P4JwxE7HgsBzech8V2nnVRgsHNXc0aeezoSGoa-uLCb6M7MXlmW_gOQppo8zOK1gb9-4jyvFeRMLwq3zUTKpK1U6yK_lZJnhvVJL5RGPLZatV1ME4bGddq8E6O339ZU/s1600/11-tube-on.JPG" height="266" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
Now, undo the two holding screws visible in the center / bottom of the picture and carefully slide the scope in.<br />
It's not difficult, but make sure the sled slides in both sides, you don't want your scope to fall on the floor! :)<br />
Lock it roughly in the middle of the sled, you will need to adjust the position later, but not yet.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimUNaBeyQ5XEJ_HuB6Q0yDjEmrjkYQvGsVLQNRQDgJeanVVvVMls369a4KIwG4nciDTIR8y7O010DO13kxQeTOf-Mrk4q7cA8_AVQq1SX3LdcyaPM78qs2vRAsUXUM8ivfNA4arxtQ0uE/s1600/12-finder.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimUNaBeyQ5XEJ_HuB6Q0yDjEmrjkYQvGsVLQNRQDgJeanVVvVMls369a4KIwG4nciDTIR8y7O010DO13kxQeTOf-Mrk4q7cA8_AVQq1SX3LdcyaPM78qs2vRAsUXUM8ivfNA4arxtQ0uE/s1600/12-finder.JPG" height="266" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
It's the turn of the finder scope, this is an easy one, just undo the locking scre, slide it in and lock it back.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw87l5Gz7SeWyxKnjGJPsvztmPGGAJFx4kSIU_819uzCYYPtH0GztRQ6eQHe907HqDxPNN13UtfD93P8U1iIhhlXWQbRuQWJyNGxswzbT94_5Ocie5VfvCyX4w5wT72u99kdOjxmacrsU/s1600/14-diagonal.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw87l5Gz7SeWyxKnjGJPsvztmPGGAJFx4kSIU_819uzCYYPtH0GztRQ6eQHe907HqDxPNN13UtfD93P8U1iIhhlXWQbRuQWJyNGxswzbT94_5Ocie5VfvCyX4w5wT72u99kdOjxmacrsU/s1600/14-diagonal.JPG" height="266" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
Time to place the diagonal on the back side of the scope.<br />
Undo the holding screws, remove the caps and fit the metallic part of the diagonal in, push it all the way before tightening the screws again.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxOCh9hyJ22slrDSe23aarupeaG5-PFcvqqbttBY5YQI1vqKcByYleh66WiTUq1K34yGKs01qaQwV9hm-4YPx85aSZRc0th4HhkmigGqdqiqDAfAtufvhliH2-gOjiIqBCRgAs4nwgitA/s1600/15-eyepiece.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxOCh9hyJ22slrDSe23aarupeaG5-PFcvqqbttBY5YQI1vqKcByYleh66WiTUq1K34yGKs01qaQwV9hm-4YPx85aSZRc0th4HhkmigGqdqiqDAfAtufvhliH2-gOjiIqBCRgAs4nwgitA/s1600/15-eyepiece.JPG" height="266" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
Similarly you install the eyepiece on the diagonal.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiq1tmdn9D5Df1sYN1srdasSIeLzQZCL06i450bgdyqN2eggKa-ckJy151ilH82x-xoSYbRXq4vx_IURnUX5DekkvUhmyjJuj01YfS0BWHiYVl4nOgPyfea5iRBONnsKVW2fZt7qMhI06Q/s1600/16-handy-holder.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiq1tmdn9D5Df1sYN1srdasSIeLzQZCL06i450bgdyqN2eggKa-ckJy151ilH82x-xoSYbRXq4vx_IURnUX5DekkvUhmyjJuj01YfS0BWHiYVl4nOgPyfea5iRBONnsKVW2fZt7qMhI06Q/s1600/16-handy-holder.JPG" height="266" width="400" /></a></div>
<div>
<br /></div>
<div>
Place the holder for the go-to controller in the slot we described before</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0gBtmtiFSeLTAfAyQ4KTM_Miak588nGXeL7dtgnvDuBxtVi35N4jNZApO919iDiZHHjZRvP4-B6Yugn3jbzcn3aBQdy5R1Y4kszQQUwGnnftyWU9pyHgAvQjBzyrjZEXTIPm_yIFoLsA/s1600/17-mount-plug.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0gBtmtiFSeLTAfAyQ4KTM_Miak588nGXeL7dtgnvDuBxtVi35N4jNZApO919iDiZHHjZRvP4-B6Yugn3jbzcn3aBQdy5R1Y4kszQQUwGnnftyWU9pyHgAvQjBzyrjZEXTIPm_yIFoLsA/s1600/17-mount-plug.JPG" height="266" width="400" /></a></div>
<div>
<br /></div>
<div>
Connect one end of the serial cable (RJ45 plug) to the mount.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz5lC9Ue4SpIzfhXdiAZ513ojhvRY7uWJgChW3GuBZu3P3h6qAHAB-Tfbpi_CbznUEtugzBjs0mPGtfrDWxgPvEvF7ElTxddhp8vCcQtnuJIjSQhHQQ3hIkZ62gnQRXT5XrjB2_5cXgHM/s1600/18-handy.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz5lC9Ue4SpIzfhXdiAZ513ojhvRY7uWJgChW3GuBZu3P3h6qAHAB-Tfbpi_CbznUEtugzBjs0mPGtfrDWxgPvEvF7ElTxddhp8vCcQtnuJIjSQhHQQ3hIkZ62gnQRXT5XrjB2_5cXgHM/s1600/18-handy.JPG" height="400" width="266" /></a></div>
<div>
<br /></div>
<div>
And the other end to the controller.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWBZLpUKFG8n710SBasQLuvcJPxVaQQeBJ_26ZJW-8tkFq2PFznTtz3K0uPAru2PgInKEP31JV6SThrN0Rx1Kft-NIvv0HRHQebLQy9Dy5pDRoUZ_HEadStYH2Q4tvtfNFbktvDwaffJI/s1600/19-balance.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWBZLpUKFG8n710SBasQLuvcJPxVaQQeBJ_26ZJW-8tkFq2PFznTtz3K0uPAru2PgInKEP31JV6SThrN0Rx1Kft-NIvv0HRHQebLQy9Dy5pDRoUZ_HEadStYH2Q4tvtfNFbktvDwaffJI/s1600/19-balance.JPG" height="266" width="400" /></a></div>
<div>
<br /></div>
<div>
We are now ready to balance the mount, sliding the counterweights as needed and also sliding the tube on the mount (undo the screws and keep the mount in the vertical position while you move the sled. Put it horizontal when you move the weights).</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2GDBLXnjKKb0c-dLPbAb7lwABYlQZt6e53iwOD-hJ7NL6nLLX5buna18J_v9KLlCmfRi5gv0AxgOfoE5Db_zW7JH5cbi2yHx9AcFgNK96NtAJacdIhwVHOtV9bqY5cC12GKUde4t84XM/s1600/20-aligning.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2GDBLXnjKKb0c-dLPbAb7lwABYlQZt6e53iwOD-hJ7NL6nLLX5buna18J_v9KLlCmfRi5gv0AxgOfoE5Db_zW7JH5cbi2yHx9AcFgNK96NtAJacdIhwVHOtV9bqY5cC12GKUde4t84XM/s1600/20-aligning.JPG" height="400" width="266" /></a></div>
<div>
</div>
<div>
That's pretty much it, now the scope is ready for the finder alignment.</div>
<div>
Make sure you do not aim it to the sun!</div>
<div>
<br /></div>
<div>
Overall first impressions, I am quite pleased with the build quality.</div>
<div>
The mount looks really sturdy and stable (it is heavy!!).</div>
<div>
Setting the thing up was not too difficult and with a bit of practice I think it can be done in few minutes (not including alignment, which I still have to explore).</div>
<div>
<br /></div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-47949162629064414652014-11-12T09:17:00.001+01:002014-11-14T08:26:06.618+01:00Space Exploration - Rosetta is about to landHello, the <a href="http://rosetta.esa.int/" target="_blank">Rosetta </a>probe reached the <a href="https://www.flickr.com/photos/europeanspaceagency/15739982196/in/set-72157638315605535/" target="_blank">Comet 67P/Churyumov-Gerasimenko</a> back in August 2014 after 10 years of flight.<br />
<br />
Rosetta is a project of <a href="http://www.esa.int/" target="_blank">ESA (European Space Agency) </a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipL57QTBMGt98EkYaE160-wkKbTbgWgM2EG-zuNv-GDphhEcqjJnRamNVXXe_nZz2lvnrK263iVc0pMGgiuNIniI7jFLQ6dXxIAhyphenhyphenMfRBzEXfXkqv4T0Kb4OJb8_Z9Jihq_05BKPqcM94/s1600/comet1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipL57QTBMGt98EkYaE160-wkKbTbgWgM2EG-zuNv-GDphhEcqjJnRamNVXXe_nZz2lvnrK263iVc0pMGgiuNIniI7jFLQ6dXxIAhyphenhyphenMfRBzEXfXkqv4T0Kb4OJb8_Z9Jihq_05BKPqcM94/s640/comet1.jpg" width="640" /></a></div>
<div style="text-align: center;">
<i><span style="font-size: x-small;">Comet 67P/Churyumov-Gerasimenko (@ESA)</span></i></div>
<br />
Today, November 12 2014 it will send a lander (Philae) to touch down on the surface of the comet, actually this is going to happen in few minutes but the radio signal will take another 28 minutes before reaching us.<br />
<br />
The Go/No Go decision was taken last night and it was not an easy one since problems were detected with a thruster that was supposed to slow down the descent.<br />
As it will not be usable, the landing structs are supposed to absorb the impact.<br />
<br />
Another issue is related to the fact that the lander will have to secure itself on the surface by drilling screws in the surface and the thruster was supposed to provide pressure to ensure this activity will not push the lander away from the surface.<br />
Hopes are the harpoons will be enough to prevent this issue.<br />
<br />
This is the first time we try to land something on a comet, it was never attempted before, so there are many things that can go wrong.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/H08tGjXNHO4?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<br />
Here the briefing<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/CBQ2svD0Zqw?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
Will update this post after the touchdown procedure is complete (fingers crossed)<br />
<br />
Landing webcast <a href="http://new.livestream.com/ESA/cometlanding" target="_blank">here</a><br />
<br />
<br />
10:05 CET - Successful separation confirmed<br />
14:20 CET circa - First images showing Philae detached from Rosetta arrived<br />
<i><span style="font-size: x-small;">Note : Lol, ESA seems to be able to reach a comet about 1.700Ls away from Earth (and hopefully land on it)... but apparently cannot manage a webcast :) And that's why they say a webcast is NOT rocket science!</span></i><br />
<i>17:04 CET - Excitement of ESA personnel seems to indicate that </i><i>telemetry data confirmed </i><i>the touchdown was successful </i><br />
<i>Currently they are trying to figure out if the lander bounced on the surface of if it managed to settle down properly.</i><br />
<i>ESA just confirmed the lander is sitting on the surface. Success!!!!</i><br />
<i><br /></i>
<br />
<div style="text-align: center;">
Captain James T. Kirk wishes good luck to Rosetta</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/yY2SGPtRmnA?feature=player_embedded' frameborder='0'></iframe></div>
<i><br /></i>
<br />
<i><br /></i>
The ROLIS instrument on board of the Philae lander module captured this image while descending to the surface<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.esa.int/var/esa/storage/images/esa_multimedia/images/2014/11/rolis_descent_image/15044808-1-eng-GB/ROLIS_descent_image_node_full_image_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.esa.int/var/esa/storage/images/esa_multimedia/images/2014/11/rolis_descent_image/15044808-1-eng-GB/ROLIS_descent_image_node_full_image_2.png" height="311" width="320" /></a></div>
<div style="text-align: center;">
<a href="http://www.esa.int/spaceinimages/Images/2014/11/ROLIS_descent_image" target="_blank">@ESA</a></div>
<br />
<span style="background-color: #999999;">"<span style="color: #031e31; font-family: verdana, arial; font-size: 12px;">The image shows comet 67P/CG acquired by the ROLIS instrument on the Philae lander during descent on Nov 12, 2014 14:38:41 UT from a distance of approximately 3 km from the surface. The landing site is imaged with a resolution of about 3m per pixel.</span></span><br />
<div style="color: #031e31; font-family: verdana, arial; font-size: 12px;">
<span style="background-color: #999999;">The ROLIS instrument is a down-looking imager that acquires images during the descent and doubles as a multispectral close-up camera after the landing. The aim of the ROLIS experiment is to study the texture and microstructure of the comet's surface. ROLIS (ROsetta Lander Imaging System) is a descent and close-up camera on the Philae Lander. It has been developed by the DLR Institute of Planetary Research, Berlin. The lander separated from the orbiter at 09:03 GMT (10:03 CET) and touched down on Comet 67P/Churyumov–Gerasimenko seven hours later."</span></div>
<div style="color: #031e31; font-family: verdana, arial; font-size: 12px;">
<br /></div>
As European tax payer, I am happy my taxes are used for this kind of purposes.<br />
<div>
More space Exploration, less jet fighters!</div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-51253340998944137502014-10-28T10:39:00.000+01:002014-10-28T10:39:50.583+01:00FTDI - was it a good move?We are all using FTDI products.<br />
They had a great idea to bring together the MCU world with modern computers.<br />
<br />
Back few years ago we all had serial ports on our computers and we used to interface microcontrollers and other stuff with them.<br />
They worked ok, but they had limitations (speed, number of devices connected...) so USB was introduced.<br />
<br />
Cool, but then all those uart based devices became hard to be connected to PCs.<br />
<br />
FTDI invented a sort of bridge between serial and usb standards, packed in a tiny chip, not difficult to use.<br />
Those chips are present in Arduino boards, in Launchpads, basically in most MCU or FPGA jtag programmers... which is great, well done FTDI.<br />
<br />
Issue is that their prices are typically quite high, sometimes exceeding the cost of the MCU you need to program, which is kind of a nonsense.<br />
Because of this a number of counterfeit chips invaded the market, damaging FTDI who rightfully holds the copyright for that technology.<br />
<br />
FTDI then decided they had to protect their IP and investments, which is understandable and took actions.<br />
<br />
<a href="http://www.eevblog.com/" target="_blank">Dave</a> @EEVBlog explains it in detail in this video<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/eU66as4Bbds?feature=player_embedded' frameborder='0'></iframe></div>
<br />
Now the issue is that FTDI decided to BRICK -render inoperative- all products that are using counterfeit chips.<br />
They posted a driver update for windows that sets to zero the productId stored in the flash rom of the chip, making it unrecognizable by the operating system.<br />
<br />
Obviously the reaction of the user community was not nice to the company and they are probably going to lose several customers.<br />
Apparently the "aggressive" driver was removed from windows update, but several products were rendered useless already.<br />
<br />
This makes me wonder few things :<br />
<br />
1) Am I ok for an OS like Windows to publish drivers that can potentially cause harm to whatever in my PC, without having the company responsible for the OS reviewing the source code and detecting eventual issues? This would not easily happen with Linux since drivers -excluding proprietary ones, which are by default disabled- are available in source code for the community to inspect.<br />
<br />
2) Isn't a bit dangerous that most of the devices we use can be easily bricked via software?<br />
Shouldn't we have some kind of repository of the config data stored in our usb devices roms, so that we could eventually re-program it if it gets damaged by malware?<br />
Shouldn't such data be writable only via an alternate interface, which is not connected to the PC?<br />
<br />
3) Is maybe the time to start pushing more USB enabled MCUs and steer away from the old uart interface? Granted, usb libraries are a bit more complex to use, maybe they should be improved... but then we would not need FTDI chips anymore.<br />
<br />
4) Shouldn't we push more for open source/hardware technology, also to protect ourselves from damages that greed (of the companies that cloned the chips and from the IP owner company as well) could damage us?<br />
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-16847637313224145752014-09-22T21:05:00.000+02:002014-09-23T13:42:09.667+02:00FPGA - 7 Segments LEDs and ROM - M9K 2What did just happen?<br />
We were discussing about RAM an now we jump into 7 segment LEDs?<br />
<br />
Yup, but no worries, we will be back to RAM in no time, we just needed this little detour because being able to use these devices in the FPGA board will help us in testing the code we write.<br />
<br />
We need something visible after all, right?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/9/97/7-segments_Indicator.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/9/97/7-segments_Indicator.gif" /></a></div>
<br />
<a href="http://fortytwoandnow.blogspot.ch/2014/09/fpga-my-second-fpga-dev-board.html" target="_blank">My FPGA Board</a> has a 6 digit 7 segments display and I plan to use it to show some Hex numbers.<br />
You are probably already familiar with how these things work, if you are not, then read on.<br />
Each digit is composed of 7 leds that are lightened up to form an image we can interpret as 0,1,2,3...<br />
To be precise normally there are 8 leds for each digit: 7 compose the digit itself and an 8th is used for the decimal point (.) .<br />
<br />
My board interfaces a 6 digit device in this way :<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoI2wuTobSw1xEj4e8M9vkjbLVsrpYER2Pgb8DouKHKgB7DRtbgedA51MfXIcodPHp0Wogp9KzA9umiFvstkALqDAzVmFWtrLoNoFhqfcmTYGUMjQDLUY-steFNLpr3Yuyi_sMp_le5oM/s1600/7segm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoI2wuTobSw1xEj4e8M9vkjbLVsrpYER2Pgb8DouKHKgB7DRtbgedA51MfXIcodPHp0Wogp9KzA9umiFvstkALqDAzVmFWtrLoNoFhqfcmTYGUMjQDLUY-steFNLpr3Yuyi_sMp_le5oM/s1600/7segm.png" height="186" width="320" /></a></div>
<br />
There are 8 outputs each one directed to a specific LED (or series of LEDs), plus 6 lines that activate the different digits.<br />
In other words, all the top leds are connected together, activated by the same output, all the center ones the same way etc etc.<br />
The 6 lines that activate specific digits are used to "scan" them.<br />
<br />
Say we want to display the value "1" in the rightmost digit.<br />
Then we will enable ONLY the line connected to tie rightmost digit, activate the top right and bottom right leds and wait for a few milliseconds.<br />
Then we will deactivate the line we used (the digit will be switched off), activate the one connected to the next digit, turn on the leds we need to represent the second digit, wait for the same amount of milliseconds etc... rinse and repeat.<br />
If the scan is fast enough, to our eyes it will look like all the digits are on at the same time.<br />
<br />
From a FPGA perspecive a viable approach would be to have one module that scans the six lines with a given clock.<br />
Another module will activate the needed segments depending on the digit that must be displayed.<br />
<br />
We will then change the value to be displayed by running a counter or something similar.<br />
<br />
Since we are using a HEX display (0..F), each digit will get exactly 4 bits of our counter.<br />
Such counter will need to cover up to 6 hex digits -> 6x4 bits -> it will be stored in a 24 bit reg.<br />
<br />
The demo module provided with my board (designed to display a decimal number, not hex) uses the following approach :<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> parameter </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> _0 = 8'b1100_0000, </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> _1 = 8'b1111_1001, </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> _2 = 8'b1010_0100,</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: xx-small;"> _3 = 8'b1011_0000, </span></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: xx-small;"> _4 = 8'b1001_1001, </span></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: xx-small;"> _5 = 8'b1001_0010, </span></span><br />
<span style="font-size: xx-small;"> <span style="font-family: 'Courier New', Courier, monospace;"> _6 = 8'b1000_0010, </span></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: xx-small;"> _7 = 8'b1111_1000, </span></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: xx-small;"> _8 = 8'b1000_0000,</span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> _9 = 8'b1001_0000;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">reg [7:0]rOne_SMG_Data;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> always @ ( posedge CLK or negedge RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> if( !RSTn )</span><br />
<span style="font-size: xx-small;"><span style="font-family: Courier New, Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> rOne_SMG_Data <= 8'b1111_1111;</span></span><br />
<span style="font-size: xx-small;"><span style="font-family: Courier New, Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> else </span></span><br />
<span style="font-size: xx-small;"><span style="font-family: Courier New, Courier, monospace;"> case( One_Data )</span><span style="font-family: 'Courier New', Courier, monospace;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>4'd0 : rOne_SMG_Data <= _0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> 4'd1 : rOne_SMG_Data <= _1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>4'd2 : rOne_SMG_Data <= _2;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>4'd3 : rOne_SMG_Data <= _3;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>4'd4 : rOne_SMG_Data <= _4;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>4'd5 : rOne_SMG_Data <= _5;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>4'd6 : rOne_SMG_Data <= _6;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>4'd7 : rOne_SMG_Data <= _7;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>4'd8 : rOne_SMG_Data <= _8;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>4'd9 : rOne_SMG_Data <= _9;</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: xx-small;">endcase</span></span><br />
<br />
<br />
Basically it defines 10 parameters with the bit patterns (active low) of the digits from 0 to 9, then it does a case statement and assigns the LEDs bus the values.<br />
I reckon it works, but, also for the sake of experimenting, I would use a different approach.<br />
My idea is to load the bit patterns in a ROM segment (16 x 8 bit words) and while displaying the digit, access the relevant ROM location to load the pattern.<br />
<br />
But first we need to have the demo work the way it is, maybe a little bit re-engineered, later on we will switch those parameters to ROM locations.<br />
<br />
The original solution (from the DVDs provided with my board) was coded with a lot of redundant code, i will not get to the details, let's just say it now works the same (in Hex instead than Decimal) with less than half of the original code.<br />
In my book that's already a good improvement, plus it was a great exercise for me.<br />
It is possible that there were good reasons for that, possibly explained in the docs and videos supporting the code, but hey, like Sandra Bullock would say: " No hablo Chino!" :)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4_a1o79GbyntwSn3FQ4jqSvszAUjdR7N4uDqJzcmgJnCTiBxZUktimbTJS3apeoWxUqjDUTVKCfnZhsM3RoVhFy3bqVTVIOJ4pi2iKem1pc8CVRi7Qxfc4bfR5l7uIMLxsqXD9PUqlU8/s1600/hie.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4_a1o79GbyntwSn3FQ4jqSvszAUjdR7N4uDqJzcmgJnCTiBxZUktimbTJS3apeoWxUqjDUTVKCfnZhsM3RoVhFy3bqVTVIOJ4pi2iKem1pc8CVRi7Qxfc4bfR5l7uIMLxsqXD9PUqlU8/s1600/hie.png" /></a></div>
<br />
<br />
The module hierarchy is represented in the image above.<br />
The top module just wires the demo_control and the smg_interface, the first one increments the counter and the second one displays it on the seven segment display.<br />
In my implementation the smg_interface module, besides wiring the other 3, implements a 1MS clock (used to scan the digits) and calculates which digit (position) should be displayed at any time.<br />
The smg_control module extracts the value of the needed digit like this :<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span style="font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> <span style="font-family: Courier New, Courier, monospace;">always @ ( posedge CLK or negedge RSTn )</span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> if( !RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> <span class="Apple-tab-span" style="white-space: pre;"> </span> rNumber <= 4'd0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> else</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> case( Scan_line )<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 0:rNumber <= Number_Sig[23:20];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> <span class="Apple-tab-span" style="white-space: pre;"> </span> 1:rNumber <= Number_Sig[19:16];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 2:rNumber <= Number_Sig[15:12];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 3:rNumber <= Number_Sig[11:8];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4:rNumber <= Number_Sig[7:4];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 5:rNumber <= Number_Sig[3:0];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>endcase</span><br />
<br />
The scan_module activates one line at a time :<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> always @ ( posedge CLK or negedge RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> if( !RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>rScan = 6'b111111;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> else </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> rScan <= ~(1 << (5-Scan_line ));<span class="Apple-tab-span" style="white-space: pre;"> </span> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> assign Scan_Sig = rScan;<span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<br />
and finally the encode one activates the led segments for the current digit<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> parameter _0 = 8'b1100_0000, _1 = 8'b1111_1001, _2 = 8'b1010_0100, </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> _3 = 8'b1011_0000, _4 = 8'b1001_1001, _5 = 8'b1001_0010, </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> _6 = 8'b1000_0010, _7 = 8'b1111_1000, _8 = 8'b1000_0000,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> _9 = 8'b1001_0000, _a = 8'b1000_1000, _b = 8'b1000_0011,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> _c = 8'b1100_0110, _d = 8'b1010_0001, _e = 8'b1000_0110,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> _f = 8'b1000_1110; </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> reg [7:0]rSMG;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> always @ ( posedge CLK or negedge RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> if( !RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> rSMG <= 8'b1111_1111;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> else </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> case( Number_Data ) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd0 : rSMG <= _0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd1 : rSMG <= _1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd2 : rSMG <= _2;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd3 : rSMG <= _3;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd4 : rSMG <= _4;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd5 : rSMG <= _5;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd6 : rSMG <= _6;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd7 : rSMG <= _7;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd8 : rSMG <= _8;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd9 : rSMG <= _9;<span class="Apple-tab-span" style="white-space: pre;"> </span> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd10 : rSMG <= _a; </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd11 : rSMG <= _b; </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd12 : rSMG <= _c; </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd13 : rSMG <= _d; </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> 4'd14 : rSMG <= _e;<span class="Apple-tab-span" style="white-space: pre;"> </span> </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"> 4'd15 : rSMG <= _f;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> endcase</span><br />
<br />
The result is visible in the video below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/MmZNd0zRXac?feature=player_embedded' frameborder='0'></iframe></div>
<br />
What we now need to change is the encode module, so that it reads the segments from memory and before that we need to create a ROM memory and populate it with the segment data.<br />
<br />
Megawizard plugin allows to create a 16 x 8 bit ROM and populate it with a mif file (see <a href="http://fortytwoandnow.blogspot.ch/2014/09/fpga-using-ram-memory-m9k-blocks-1.html" target="_blank">previous post</a>, same steps, but this time I chose 1 Port ROM instead of RAM).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbUWBkWiCnQrstLvjzLobgb30IgLiKvgQR-sOlv6I1NfZdUfX3ylhmxAMioujEYFqaPBlFaSe0fLq4CJSo_qnibRWAutSheVqXeTP-sv5xMMLARu-N1JOfljuvjtq1H3MXeNbS_l_8m5g/s1600/rom.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbUWBkWiCnQrstLvjzLobgb30IgLiKvgQR-sOlv6I1NfZdUfX3ylhmxAMioujEYFqaPBlFaSe0fLq4CJSo_qnibRWAutSheVqXeTP-sv5xMMLARu-N1JOfljuvjtq1H3MXeNbS_l_8m5g/s1600/rom.png" height="351" width="400" /></a></div>
<br />
<br />
Then we simply substitute the encode module with the newly created rom module in smg_interface:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">// remove the old one </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> /*smg_encode_module U2</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> (</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> .CLK( clk2 ),</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> .RSTn( RSTn ),</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> .Number_Data( Number_Data ), // input - from U2</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> .SMG_Data( SMG_Data ) // output - to top</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> );*/</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">// add the new one </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> digit_rom rom(</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> .address(Number_Data),</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> .clock(clk2),</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> .q(SMG_Data)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>);</span><br />
<br />
Done!<br />
Can it get any simpler than that?<br />
And yes, it works of course, will not upload a video proof as it is boringly identical to the previous, but it really works!<br />
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-59012205142025429322014-09-21T16:34:00.001+02:002014-09-21T16:40:55.230+02:00FPGA - Using RAM Memory - M9K Blocks 1We all know that MCUs are easier than normal CPUs because pretty much all you need for an application is "included", particularly a certain amount of RAM.<br />
<br />
FPGAs are no different, in fact most of them include a number of ram blocks (called M9K in Altera Cyclone IV devices, or M4K in Cyclone II ones... not sure about the other families).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfJURatR6x-wMjOsIrtXc5WMAQGPD-OlA1VNeccsHoGnEHxWqWZUpcmHgzTJlTkk3CZUtatc9MZewW_5hIIFmGGWBAUEGAFLmBKh9Q3aSRCmZvFSsgUvVdUy4utc5bJSjzupTD-8MPZDE/s1600/memtype.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfJURatR6x-wMjOsIrtXc5WMAQGPD-OlA1VNeccsHoGnEHxWqWZUpcmHgzTJlTkk3CZUtatc9MZewW_5hIIFmGGWBAUEGAFLmBKh9Q3aSRCmZvFSsgUvVdUy4utc5bJSjzupTD-8MPZDE/s1600/memtype.png" height="153" width="400" /></a></div>
<div style="text-align: center;">
<i><span style="font-size: x-small;">(available memory blocks by family - From <a href="http://www.altera.com/literature/ug/ug_ram_rom.pdf" target="_blank">Altera's documentation</a>)</span></i></div>
<br />
<br />
If you want to implement a CPU within your FPGA (typically a NIOS II, but any CPU would have the same requirement), you need some ram to store the code to be executed and eventual data.<br />
<br />
Since FPGAs have a high count of I/O pins, you can dedicate a few of them to interface an external memory chip or you can use the internal one.<br />
<br />
Altera M9K memory blocks are 9KBit memory blocks that can be organized in different ways (i.e. in 9 bit words x 1K cells).<br />
The motivating reason to have 9 bits instead of 8 is to have an additional bit for parity control.<br />
<br />
Different devices have a different amount of M9K blocks, the following table lists the specs of the Cyclone IVE family.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQBlJflDTLG_Yx5B2fYJ-ZoyK0ZfoLnEdD-f7LsBF1z1fsH_mERVhYfcIyYXVkMt-HJSZXC_-Wg0kCaA3-HOtBt_BCVAs1QKyzL-lmpK4WNXVfqPX9UG3zoxa9tBPTsYSb8P9jKfFi2HE/s1600/c4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQBlJflDTLG_Yx5B2fYJ-ZoyK0ZfoLnEdD-f7LsBF1z1fsH_mERVhYfcIyYXVkMt-HJSZXC_-Wg0kCaA3-HOtBt_BCVAs1QKyzL-lmpK4WNXVfqPX9UG3zoxa9tBPTsYSb8P9jKfFi2HE/s1600/c4.png" height="202" width="400" /></a></div>
<div style="text-align: center;">
<i><span style="font-size: x-small;"> ( from <a href="http://www.altera.com/literature/hb/cyclone-iv/cyiv-51001.pdf" target="_blank">Altera's website</a> )</span></i></div>
<br />
One interesting feature of these memory blocks is that they are Dual Ported.<br />
This means that they can be configured in a way that allows reading and writing from different addresses and data busses.<br />
Does it matter?<br />
I guess sometimes it does, think about a VGA interface, like the one we described in<a href="http://fortytwoandnow.blogspot.ch/2014/09/fpga-vga-interface-1.html" target="_blank"> the previous post</a>.<br />
<br />
The VGA implementation we did, did not use memory, it was simply calculating the RGB components based on the X/Y coordinates, using a binary formula.<br />
For practical uses you will hardly use that approach, instead you will probably have a process that writes data in a memory bank where memory locations represent pixels and all together form an image.<br />
Another, concurrent, process will read sequentially the memory bank and use the content to drive the color components.<br />
Technically this means one process will write in some random location L(x1,y1) while another will read from L(x2,y2)<u> at the same time</u>.<br />
If the two processes can use separate ports, the problem is solved!<br />
<br />
<i><span style="font-family: inherit; font-size: xx-small;"><b>Note : </b>I cannot compare the quality of Altera's documentation with the one provided by competitors since I only used Altera's when dealing with FPGAs, I can only say <u>it is GREAT</u>.</span></i><br />
<i><span style="font-family: inherit; font-size: xx-small;">There is a ton of useful documentation, examples, tutorials, online training etc available on the Altera website.</span></i><br />
<br />
<a href="http://www.altera.com/literature/ug/ug_ram_rom.pdf" target="_blank">Here</a> I found an example implementation of a true dual port memory block :<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">module true_dp_ram (</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>address_a,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>address_b,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>clock,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>data_a,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>data_b,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>rden_a,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>rden_b,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>wren_a,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>wren_b,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>q_a,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>q_b);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>[3:0] address_a;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>[3:0] address_b;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>clock;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>[12:0] data_a;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>[12:0] data_b;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>rden_a;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>rden_b;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>wren_a;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>wren_b;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>output<span class="Apple-tab-span" style="white-space: pre;"> </span>[12:0] q_a;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>output<span class="Apple-tab-span" style="white-space: pre;"> </span>[12:0] q_b;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">[...]</span><br />
<br />
As you can see this example implements two 4 bits addresses, two separate 13 bits inputs and two 13 bits outputs.<br />
Additional inputs are the clock (RAM needs one) and the read enable / write enable for each port.<br />
How cool is that?!!<br />
<br />
Obviously you can trim down your requirements and work with a simpler 1 Port interface if this is ok with your design.<br />
<br />
Once you create a memory block, you can specify an initialization file in Quartus II, meaning that your memory could be populated at reset.<br />
Problem is that to actually test if the memory works, we need to provide some kind of output, so we will use in our first example just a few LEDs which will represent the bits of the memory locations we will scan (slowly, so we can see them change).<br />
<br />
A common way to provide init data is through a MIF file, <a href="http://www.mil.ufl.edu/4712/docs/mif_help.pdf" target="_blank">follow this link </a>to see the specs.<br />
<br />
The MegaWizard plugin manager comes handy here :<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0HOwB6W29PEXdp_tCikpVIDjJSCJksvPpaY9hI3X9oyJk_77PpQH5i33hDRy7EvwYPBygU-MCf3BEUXOl_NIDF60J5QPW-8_CXhmW5tUruWXeePzNbj6JcCH-5doAieeUG5Z7ZpoisIs/s1600/ram1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0HOwB6W29PEXdp_tCikpVIDjJSCJksvPpaY9hI3X9oyJk_77PpQH5i33hDRy7EvwYPBygU-MCf3BEUXOl_NIDF60J5QPW-8_CXhmW5tUruWXeePzNbj6JcCH-5doAieeUG5Z7ZpoisIs/s1600/ram1.png" height="266" width="400" /></a></div>
<br />
A simple 1 Port ram here, for this test<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIisjbmQPG1mG4ExRMWF3rKJCilA4n1ZW7GCrYjLNRNELLxY8Kqfctefe0om55ZnPSCDIwctR1wCSOKTuI5FyY0VTx8uGl9Jbm1P8tzfEBnlHEOn9H6tM8klAvWtNuUAkhCqvxKbzMLUQ/s1600/ram2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIisjbmQPG1mG4ExRMWF3rKJCilA4n1ZW7GCrYjLNRNELLxY8Kqfctefe0om55ZnPSCDIwctR1wCSOKTuI5FyY0VTx8uGl9Jbm1P8tzfEBnlHEOn9H6tM8klAvWtNuUAkhCqvxKbzMLUQ/s1600/ram2.png" height="370" width="400" /></a></div>
<br />
I am planning to use 4 LEDs to output the values, so it is handy to have 4 bits wide words, I chose an arbitrary length of 32, should be more than enough to verify my pattern.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6HNWunDDT2ls-fvhx08Z8vWb4u6dT26fcNHIZllv4I18DFFu04nQIwjbpbK7ybWWE5WVQvjM_fMiQV6EUQaIJjMgw4c6vMZ8Wy55cXN9Z_tpXZBrIcXPxGdINDKwkKxDLk9Nl1vSMMH0/s1600/ram3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6HNWunDDT2ls-fvhx08Z8vWb4u6dT26fcNHIZllv4I18DFFu04nQIwjbpbK7ybWWE5WVQvjM_fMiQV6EUQaIJjMgw4c6vMZ8Wy55cXN9Z_tpXZBrIcXPxGdINDKwkKxDLk9Nl1vSMMH0/s1600/ram3.png" height="345" width="400" /></a></div>
<br />
Finally I created a MIF file and loaded it here (it is possible to update it later, even without recompiling the project).<br />
<br />
The result is a new module which looks like this :<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">module ram_module (</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>address,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>clock,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>data,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>wren,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>q);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>[4:0] address;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>clock;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>[3:0] data;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>input<span class="Apple-tab-span" style="white-space: pre;"> </span>wren;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>output<span class="Apple-tab-span" style="white-space: pre;"> </span>[3:0] q;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">[...]</span><br />
<br />
As you can see it created a 5 bit address (we have 32 locations), and two registers for input and output, 4 bit wide each as requested.<br />
Wren will be used to write data, meaning that for this initial test it will not be used at all (so ROM memory would have produced the same result after all :) )<br />
<br />
Ok, so now we need a top module that cycles the ram buffer and outputs the content to the leds.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">module m9ktest_top(leds ,clock, reset );</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">output reg[3:0] leds;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">input clock;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">input reset;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">reg write;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">reg [4:0] addr;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">reg [3:0] datain;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">wire [3:0] dataout;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">reg ramclk;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">// instantiate and connect the ram buffer</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">ram_module buffer</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">(</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>.address(addr),</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>.clock(ramclk),</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>.data(datain),</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>.wren(write),</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>.q(dataout)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">reg [31:0] counter; //24 bits would have been enoguh</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">wire CounterMaxed = (counter==32'hFFFFFF);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">always @ (posedge clock or negedge reset)// on positive clock edge</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">begin </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if (!reset)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> begin // initial conditions</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> addr <= 5'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> ramclk <= 1'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> counter <= 32'h0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> write <= 1'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">end else if(CounterMaxed)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">begin</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> counter <= 32'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> addr <= addr + 5'b1; // set address</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> write <= 1'b0; // disable write</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> ramclk <= 1'b1; // clock the ram</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> leds <= dataout; // read ram location </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if (addr == 5'b11111)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> addr <= #1 5'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> end</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">else</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> begin </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">// just delay, my eyes are not fast enough for MHz range!</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> ramclk <= 1'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> counter <= counter + 32'b1;// increment counter</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> end</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">end </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">endmodule</span><br />
<br />
I know, it is not really elegant and I am sure it can be coded much better, bear with me, this is still one of my first Verilog experiments.<br />
If you have suggestion / corrections, tho, make sure to post them in the comments!<br />
<br />
So, what to say about the code?<br />
It is pretty self explanatory, actually the particular thing is that I am clocking the ram only when I need to read it (is it ok? Best practices? not sure there)<br />
You will notice there is a single always block that is sensitive to both reset and main clock, this is because in Verilog you cannot manipulate the same signal from two different processes.<br />
Makes sens if you think about it : altering the same signal in two independent processes would result in unpredictable results, after all.<br />
<br />
Ah, it works by the way :)<br />
Honestly I was really surprised it did work immediately, first attempt... guess I just got lucky, but that wouldn't have been possible without the great docs I already mentioned in this post, kudos to Altera for that one.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/15LuiuoXBC4?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-49524242378755719172014-09-07T10:29:00.000+02:002014-09-07T10:37:12.031+02:00FPGA - VGA Interface / 2In the<a href="http://fortytwoandnow.blogspot.ch/2014/09/fpga-vga-interface-1.html" target="_blank"> previous post</a> I discussed the VGA standard and the implementation of a<br />
vga_sync module using Verilog.<br />
<br />
In this post we will try to understand how to use such sync module to output some graphics from the FPGA to a VGA compatible monitor,<br />
<br />
Before going into that, a small issue I encountered with my FPGA board :<br />
<br />
When outputting rgb colors from it, I clearly get a voltage which is lower than the expected 0.7V maximum, since the colors I can see on the monitor are pretty dark.<br />
I initially thought that the I/O Bank used by signals was wrongly set to 2.5 or less Volts instead of 3.3V... but checking in Quartus II I found it was correctly set.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf5C8EAH-KPnvFgV00nMTGI91VjcpNaXquXqi3Rj_Anpa_PQ0XAElH9qokY7fYYwbyKKkRnanj-VE3e-Yp3VJYBEcqslDOqpqQKlJeFOVDZXiDamvIjBzujkWVYaRBi5RinEflKgV0B_U/s1600/iobank.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf5C8EAH-KPnvFgV00nMTGI91VjcpNaXquXqi3Rj_Anpa_PQ0XAElH9qokY7fYYwbyKKkRnanj-VE3e-Yp3VJYBEcqslDOqpqQKlJeFOVDZXiDamvIjBzujkWVYaRBi5RinEflKgV0B_U/s1600/iobank.png" height="100" width="400" /></a></div>
<br />
So, I wondered if the board designer / manufacturer chose the wrong resistors for the R,G and B signals (expecting 270 or 330 Ohm maximum)...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnPnpq7cU8NfgFGZWfJ7c16F9UbEflJ0G6dQj9ZmjpWrYHDSVPLppExx0UWixIB7GAtL1FdangAydAVAPfZKMre7Js9zJWfN2i3QsUZjjxhjfxxeJmrLfUPSAjeYwzg69J6LgkE9wAxnc/s1600/wrong_resistors.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnPnpq7cU8NfgFGZWfJ7c16F9UbEflJ0G6dQj9ZmjpWrYHDSVPLppExx0UWixIB7GAtL1FdangAydAVAPfZKMre7Js9zJWfN2i3QsUZjjxhjfxxeJmrLfUPSAjeYwzg69J6LgkE9wAxnc/s1600/wrong_resistors.png" height="183" width="320" /></a></div>
<br />
1K ?? Seriously??!! I mean, dude (or dudes/gals), whoever you are, you designed a wonderful board with LCD, RAM etc... and you fail a voltage divider calculation??!!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/3/3b/Paris_Tuileries_Garden_Facepalm_statue.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/3/3b/Paris_Tuileries_Garden_Facepalm_statue.jpg" height="213" width="320" /></a></div>
<div>
<br />
I don't know, there might be good reasons for going for very dark colors and anyhow I think I could fix the issue by soldering resistors in parallel.<br />
<br />
<b><span style="color: yellow;">Implementing the control module</span></b><br />
<br />
Again, I am illustrating the example provided with my board, check previous post for details.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">module vga_control_module</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">(</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> CLK, RSTn,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> Ready_Sig, Column_Addr_Sig, Row_Addr_Sig,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> Red_Sig, Green_Sig, Blue_Sig</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> input CLK;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> input RSTn;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> input Ready_Sig;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> input [10:0]Column_Addr_Sig;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> input [10:0]Row_Addr_Sig;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> output Red_Sig;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> output Green_Sig;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> output Blue_Sig;</span><br />
<br />
This module gets the clock and reset signals from external pins and receives Ready_Sig plus the X and Y counters from the sync_module (check <a href="http://fortytwoandnow.blogspot.ch/2014/09/fpga-vga-interface-1.html" target="_blank">previous post</a> for a detailed explanation).<br />
It uses all this information to drive the three color components which, in the case of my board, are single bit, but it would be quite easy to provide a resistor based DAC to give more color depth and driving it with multiple bits.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.xess.com/static/media/uploads/blog/devbisme/2011-06-02/VGA_DAC.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.xess.com/static/media/uploads/blog/devbisme/2011-06-02/VGA_DAC.png" height="315" width="320" /></a></div>
<div style="text-align: center;">
(<a href="http://www.xess.com/blog/a-simple-vga-interface-for-the-xula-fpga-board/" target="_blank">from xess.com</a>)</div>
<br />
<br />
<br />
Back to our module, at this point we need to use the X / Y coordinates to assign a value to the R, G and B components.<br />
In my example I will use a condition, but eventually you might fetch the value from RAM and display an image.<br />
<br />
what I did was to add a 4 bit counter i and use it to generate binary color patterns<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> <span class="Apple-tab-span" style="white-space: pre;"> </span> reg [3:0]i;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> always @ ( posedge CLK or negedge RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> if( !RSTn ) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> i <=4'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>else if (Column_Addr_Sig == 11'd0 && Row_Addr_Sig == 11'd0) i <= 4'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> else if (i == 4'b1111) i <=4'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> else i <= i + 1'b1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> assign Red_Sig = Ready_Sig && Column_Addr_Sig[i];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> assign Green_Sig = Ready_Sig && Row_Addr_Sig[i];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> assign Blue_Sig = Ready_Sig && Row_Addr_Sig[2];</span><br />
<br />
As you can see the Red and Green signals use the "i" bit of the X and Y coordinates, while the Blue signal always uses the third bit (2) of the Y coordinates (which will generate 8 pixel "fat" horizontal lines).<br />
All the signals are masked with Ready_Sig to ensure they are silent outside the active area as per VGA specs.<br />
<br />
Ah, by the way, in case you are wondering what the condition<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">else if (Column_Addr_Sig == 11'd0 </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> && Row_Addr_Sig == 11'd0) i <= 4'b0;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: inherit;">is for, this is just to reset the i counter at the beginning of the frame, so that I can get a still image, else it might change at every frame since i is used together with X and Y. </span><br />
<span style="font-family: inherit;">Also note that in my experiment I did not use a 100MHz clock, this is important because i is incremented at every clock, you might need to adjust that part if you are using a clock higher than the pixel clock (well, you might just get a different color pattern).</span><br />
<span style="font-family: inherit;"><br /></span>
Finally you just need to wire everything together in a top_level design and assign the pins.<br />
This is the result I obtained :<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_bDdqhwB1159E0-KbdzxRTQrTUQ98Xp9BndSslgQm8_0xYQOyyTUXFdA6dwmmbCcFuZJai6SXKDl5gIGhaQQNxMWW5SBKtSKsUmbj9idR4uxeSbrctJGG2j1pzSJV_fWwQMvXAopqeVA/s1600/IMG_4327.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_bDdqhwB1159E0-KbdzxRTQrTUQ98Xp9BndSslgQm8_0xYQOyyTUXFdA6dwmmbCcFuZJai6SXKDl5gIGhaQQNxMWW5SBKtSKsUmbj9idR4uxeSbrctJGG2j1pzSJV_fWwQMvXAopqeVA/s1600/IMG_4327.JPG" height="300" width="400" /></a></div>
<br />
If we can consider this a form of art, I'd like to call this piece : "<i>Art that makes sense, in a binary way</i>".<br />
<br />
:)<br />
<br /></div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-64013223884197159002014-09-06T17:03:00.001+02:002014-09-06T17:03:22.953+02:00FPGA - VGA Interface / 1Ahhhh, remember when we used CRT monitors?<br />
If you don't, then, good for you, as you are probably really young or lived far away from technology!<br />
Does it matter when dealing with VGAs?<br />
Yest it does, as that standard was created to work with CRT monitors and even if we are not using them anymore, we still need to to follow crt related rules when we want to use it.<br />
<br />
If you want to know more about <b>C</b>athode <b>R</b>ay <b>T</b>ubes, you can check <a href="https://project-physicsteaching.web.cern.ch/project-physicsteaching/english/experiments/cathode-ray-tube.pdf" target="_blank">this interesting article</a> from CERN.<br />
<br />
Ok, so, VGA is an analog system that uses 3 color components (R,G,B) that are provided with 3 different signals that ranges from 0 to 0.7V.<br />
0.7V means maximum intensity for every single color component and by varying the voltages of the three lines you can generate virtually all the RGB additive colors.<br />
Easy enough, right?<br />
There are other two signals, used to generate a vertical (VS) and an horizontal sync (HS).<br />
<br />
If you know (or checked the linked article) how a CRT works, you also know that an electric and a magnetic fields are used to deflect horizontally and vertically the electrons emitted by the hot cathode, in their path to the screen (anode).<br />
In CRT televisions and analog monitors, this deflection is programmed to be a scan from top to bottom and from left to right.<br />
Those HS and VS signals tell the monitor at which speed they should perform such scan.<br />
I.e. in the standard 640x480 VGA resolution , VS is 60Hz and HS is 31.5KHz (<i>actually 31.4685KHz according to the specs</i>).<br />
<br />
This means that the CRT will be ready to retrace a new frame 60 times per second and within each frame it will be restarting a new horizontal line 31.500 times per second.<br />
<br />
If you do the math, you will discover that this allows us to theoretically have 31.500 / 60 = 525 lines per frame.<br />
<br />
We said before the resolution is supposed to be 480 lines, which is slightly less than the 525 we found.<br />
That's why I said <u>theoretically.</u><br />
What happens is that the old CRT technology needed some time to adjust the magnetic and electric fields so that a new line and/or a new frame could be started.<br />
This would not be the case with the current technology, still the VGA standard assumes that your R,G and B signals are silent (0V) at the beginning and at the end of a Horizontal or Vertical scan period.<br />
Practically it means that you will need to generate a sync for 525 lines and ensure that (525-480)/2 at the border (called front porch and back porch) are kept completely black.<br />
Same thing for the vertical border, the internal circuitry of a VGA monitor will likely assume you have about 800 columns, 640 of which are usable.<br />
Technically you should calculate the borders as times, not rows and columns, but in a mcu or fpga implementation it just becomes easier to calculate them as rows and columns since you are calculating those anyways.<br />
<br />
Actual numbers may vary, particularly when using multisync monitors, you may need to adjust this "grace period" describing the border around your usable area according to your monitor.<br />
<br />
Technical specifications <a href="http://en.wikipedia.org/wiki/Video_Graphics_Array" target="_blank">(source wikipedia</a>) for the horizontal timing are the following :<br />
<table class="wikitable" style="background-color: #f9f9f9; border-collapse: collapse; border: 1px solid rgb(170, 170, 170); color: black; font-family: sans-serif; font-size: 17.27272605896px; line-height: 25.4545440673828px; margin: 1em 0px;"><tbody>
<tr><th style="background-color: #f2f2f2; border: 1px solid rgb(170, 170, 170); padding: 0.2em; text-align: center;">Parameter</th><th style="background-color: #f2f2f2; border: 1px solid rgb(170, 170, 170); padding: 0.2em; text-align: center;">Value</th><th style="background-color: #f2f2f2; border: 1px solid rgb(170, 170, 170); padding: 0.2em; text-align: center;">Unit</th></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Pixel clock frequency</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">25.175</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"><a href="http://en.wikipedia.org/wiki/Hertz" style="background: none; color: #0b0080; text-decoration: none;" title="Hertz">MHz</a><sup class="reference" id="cite_ref-10" style="font-size: 13.63636302948px; line-height: 1; unicode-bidi: -webkit-isolate;"><a href="http://en.wikipedia.org/wiki/Video_Graphics_Array#cite_note-10" style="background: none; color: #0b0080; text-decoration: none; white-space: nowrap;">[10]</a></sup></td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Horizontal frequency</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">31.469</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"><a href="http://en.wikipedia.org/wiki/Hertz" style="background: none; color: #0b0080; text-decoration: none;" title="Hertz">kHz</a></td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Horizontal pixels</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">640</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"></td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Horizontal sync polarity</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Negative</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"></td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Total time for each line</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">31.778</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"><a class="mw-redirect" href="http://en.wikipedia.org/wiki/1_E-6_s" style="background: none; color: #0b0080; text-decoration: none;" title="1 E-6 s">µs</a></td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"><a class="mw-redirect" href="http://en.wikipedia.org/wiki/Front_porch" style="background: none; color: #0b0080; text-decoration: none;" title="Front porch">Front porch</a> (A)</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">0.636</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">µs</td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Sync pulse length (B)</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">3.813</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">µs</td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"><a class="mw-redirect" href="http://en.wikipedia.org/wiki/Back_porch" style="background: none; color: #0b0080; text-decoration: none;" title="Back porch">Back porch</a> (C)</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">1.907</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">µs</td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Active video (D)</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">25.422</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">µs</td></tr>
</tbody></table>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/3/32/VGA_640x480_H-Timing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/3/32/VGA_640x480_H-Timing.png" height="130" width="640" /></a></div>
<br />
<br />
and for the vertical Timing<br />
<br />
<table class="wikitable" style="background-color: #f9f9f9; border-collapse: collapse; border: 1px solid rgb(170, 170, 170); color: black; font-family: sans-serif; font-size: 17.27272605896px; line-height: 25.4545440673828px; margin: 1em 0px;"><tbody>
<tr><th style="background-color: #f2f2f2; border: 1px solid rgb(170, 170, 170); padding: 0.2em; text-align: center;">Parameter</th><th style="background-color: #f2f2f2; border: 1px solid rgb(170, 170, 170); padding: 0.2em; text-align: center;">Value</th><th style="background-color: #f2f2f2; border: 1px solid rgb(170, 170, 170); padding: 0.2em; text-align: center;">Unit</th></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Vertical lines</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">480</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"></td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Vertical sync polarity</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Negative</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"></td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Vertical frequency</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">59.94</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Hz</td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Total time for each frame</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">16.683</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">ms</td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Front porch (A)</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">0.318</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;"><a href="http://en.wikipedia.org/wiki/Millisecond" style="background: none; color: #0b0080; text-decoration: none;" title="Millisecond">ms</a></td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Sync pulse length (B)</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">0.064</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">ms</td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Back porch (C)</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">1.048</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">ms</td></tr>
<tr><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">Active video (D)</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">15.253</td><td style="border: 1px solid rgb(170, 170, 170); padding: 0.2em;">ms</td></tr>
</tbody></table>
However chances are that you are going to use a modern monitor, which typically can accept some "flexibility" on those timings.<br />
<div>
<br /></div>
<div>
All in all the HW interface is quite simple as you can see in the picture below (from <a href="http://www.fpga4fun.com/">www.fpga4fun.com</a>) .<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.fpga4fun.com/images/VGAconnector.2.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.fpga4fun.com/images/VGAconnector.2.gif" height="210" width="320" /></a></div>
<br />
<br />
The 270Ohm resitors are used to generate a voltage divider with the internal impedance of 75Ohm which, supplied with a 3.3V voltage, would give us roughly the needed 0.7V.<br />
<br />
Ok, all this is cool, but how does it fit in the FPGA design?<br />
Of course this would work nicely with an MCU or an FPGA, but I think the FPGA solution is more appropriate in this case since you can dedicate some internal circuitry to handle the synchronization signals and have it work in parallel with your solution.<br />
<br />
One way to go is to design a <b>vga_synch</b> module that generates the HS and VS signals, plus calculates the current X & Y coordinates.<br />
Then we will have another module to use such coordinates in order to calculate R,G and B based on a mathematical formula, conditions or reading values from RAM (like it happens in a PC VGA card).<br />
<br />
<b><span style="color: yellow;">Implementation of the sync module</span></b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
For practical reasons (this is also the case in real world applications), one single clock will be used for both the HS and VS signals, so VS will have a period which is an integer multiple of the HS period.<br />
Also, we will use the same base clock to calculate the width of those signals and every single pixel.<br />
<br />
Instead of creating my own module I will present the one provided with my FPGA board, so credits goes to some unknown author.<br />
I will however deeply comment every single part of it, comments are mine, therefore all the shame deriving from possible mistakes goes to me :)<br />
<br />
Before discussing the module itself, I have to specify that the clk signal is obtained by multiplying by two (in a pll) the board 50MHz clock, so it is a 100MHz clock fed to the sync module.<br />
I don't know why they decided for this frequency since they are then dividing it by 4 in the Verilog module and nowhere the 100MHz frequency seems to be used.<br />
They could have just divided by two the 50MHz and skip the pll.. but maybe this module was used also for higher resolutions.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">module sync_module</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">(</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> CLK, RSTn,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> VSYNC_Sig, HSYNC_Sig, Ready_Sig,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> Column_Addr_Sig, Row_Addr_Sig</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> input CLK;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> input RSTn;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> output VSYNC_Sig;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> output HSYNC_Sig;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> output Ready_Sig;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> output [10:0]Column_Addr_Sig;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> output [10:0]Row_Addr_Sig;</span><br />
<br />
All this just defines an input clock (the 100MHz we discussed before) and reset, plus the 5 outputs being HS,VS, the X counter, the Y counter and a flag (Ready_Sig) which accounts for the front/back porch times.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> parameter T40NS = 3'd3;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> reg [2:0]Count1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> always @ ( posedge CLK or negedge RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> if( !RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> Count1 <= 3'd0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> else if( Count1 == T40NS )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> Count1 <= 3'd0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> else </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> Count1 <= Count1 + 1'b1;</span><br />
<br />
This part is just used to implement the needed division by 4.<br />
The variable Count1 is used and when it equals 3 (3'd3) it means 4 clock cycles passed (0 to 3), in other words a time lapse of 40ns (1/25MHz).<br />
Conditions are : At reset restart from zero, at max count (T40NS) restart from zero, else just increment.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> reg [10:0]Count_H;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> always @ ( posedge CLK or negedge RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> if( !RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> Count_H <= 11'd0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> <span class="Apple-tab-span" style="white-space: pre;"> </span>else if( Count_H == 11'd800 )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> Count_H <= 11'd0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>else if( Count1 == T40NS )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> Count_H <= Count_H + 1'b1;</span><br />
<br />
Now we calculate the X counter (at each clock)<br />
The counter itself is defined as a 11bit number <span style="font-family: Courier New, Courier, monospace; font-size: x-small;">reg [10:0]Count_H; </span>(which also makes us think this module might have been used for higher resolutions, since for the 640 one 10 bits would have been enough).<br />
At reset, as usual, start all over from zero, if we reached column 800 -see, we calculate front porch and back porch as columns instead of times, it's easier this way!- then back to column zero else IF we are at the 25MHz marker (Count1 maxed) increase the X counter.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> reg [10:0]Count_V;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> always @ ( posedge CLK or negedge RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if( !RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> Count_V <= 11'd0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> else if( Count_V == 11'd525 )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> Count_V <= 11'd0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> else if( Count_H == 11'd800 )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> Count_V <= Count_V + 1'b1;</span><br />
<br />
The Y counter mechanism is similar, with the only difference that it is reset to 0 when it reaches 525 and it is incremented when the X counter is maxed.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> reg isReady;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> always @ ( posedge CLK or negedge RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if( !RSTn )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> isReady <= 1'b0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> else if( ( Count_H >= 11'd144 </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> && Count_H < 11'd784 ) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> &&</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> ( Count_V >= 11'd35 </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> && Count_V < 11'd515 ) )</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> isReady <= 1'b1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> else</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> isReady <= 1'b0;</span><br />
<br />
Now the isReady flag is calculated, it tells us if we are in the usable XY area or if we are in those black borders in which our R,G and B signals should be kept silent.<br />
isReady is set true when X is between 144 and 784 (if you subtract them you obtain 640) and Y is between 35 and 515 (guess what you get if you subtract them? :) )<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">assign VSYNC_Sig = ( Count_V <= 11'd2 ) ? 1'b0 : 1'b1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">assign HSYNC_Sig = ( Count_H <= 11'd96 ) ? 1'b0 : 1'b1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">assign Ready_Sig = isReady; </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">assign Column_Addr_Sig = isReady ? Count_H - 11'd144 : 11'd0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">assign Row_Addr_Sig = isReady ? Count_V - 11'd35 : 11'd0; </span><br />
<br />
Finally VS and HS are calculated based on the X and Y counters, their duration is respectively 3 rows and 97 columns (you can convert these in times if you like).<br />
Also note these signals are negative.<br />
Finally the real coordinates are computed (if we are in the usable area, identified by isReady = true) by subtracting the left and top border.<br />
<br />
Will close it here today, going to explain the control module in the next post, but that's the easy part.<br />
<br /></div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-41389583553502250762014-09-04T09:51:00.000+02:002014-09-04T09:51:42.943+02:00FPGA - My second FPGA dev boardI am back playing with FPGAs.<br />
Meanwhile I bought a new FPGA borad, not that the tiny one I already had did not do, but I found that connecting and disconnecting stuff all the time to the GPIO was not really a convenient way to go.<br />
So I went for another Cyclone IV board, a bit more expensive, but it has a bit of everything onboard.<br />
Most of all it has external SDRAM, a VGA connector, Ethernet, an internal B/W LCD, some 7 segment leds, USB, a buzzer...<br />
Looks like a perfect platform for Nios II stuff.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFjF2tRFgIdFkMIL3vsC5h3HtAiSGA9vOtZUUBu6jbfAL__pL9yHmIuHAvhMsgSWGhyXusac8uc1QUWn0zOkVRNt0hBekxdQ7pUbo4pBk7O5nsvzwk3amLGZXuitdDFpBV2o3ol3SCqV8/s1600/IMG_4317.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFjF2tRFgIdFkMIL3vsC5h3HtAiSGA9vOtZUUBu6jbfAL__pL9yHmIuHAvhMsgSWGhyXusac8uc1QUWn0zOkVRNt0hBekxdQ7pUbo4pBk7O5nsvzwk3amLGZXuitdDFpBV2o3ol3SCqV8/s1600/IMG_4317.JPG" height="300" width="400" /></a></div>
<br />
This board is a<b> Black Gold Cyclone IV EPCE15</b> (15K LEs) which seems to be designed and built with some quality criteria in mind.<br />
Not sure what the exact brand is as I found references to Alinx, heijin.org and OSH (you can see an OSH logo in the picture, top right).<br />
The url on the bottom right part says http://oshcn.com , but that appears to be a domain for sale :)<br />
<br />
Ok, not exactly a Terasic product, we get it, right?<br />
Still they went the extra mile and packaged the whole thing in two plastic transparent sheets (laser cut), PCB finish seems to be really nice and you get an amazingly good looking box which even has magnets to keep the front flap closed (I know, it is a tiny useless detail, but at least it shows they are trying to give a quality image, which never hurts).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTScalwVZ3s_PU5IFCBkeP69p_scQxDUEaFhDqldl55HQL2xlcmSv-eJq_sEd-OYAAFdRjd7DFNncwBLKGRotB3UZLHQ20nWTZxhhOB-xibwTgjWSx3-c-wXCUsTu_3w60Muajg9KbURk/s1600/IMG_4331.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTScalwVZ3s_PU5IFCBkeP69p_scQxDUEaFhDqldl55HQL2xlcmSv-eJq_sEd-OYAAFdRjd7DFNncwBLKGRotB3UZLHQ20nWTZxhhOB-xibwTgjWSx3-c-wXCUsTu_3w60Muajg9KbURk/s1600/IMG_4331.JPG" height="300" width="400" /></a></div>
<br />
In my case the box contained the assembled board, a psu, an usb blaster with cables and a vga cable plus a container with 3 DVDs.<br />
Yup, 3 DVDs of docs, samples, software, videos illustrating every single experiment included... which is all great <u>provided you can read Chinese</u>.<br />
It seems there are detailed instructions for every single step, every single detail, but not a word in English.<br />
Actually the parts datasheets are in English once you find them in a folder structure that has Chinese directory names.<br />
Same thing if you try to find something in internet, looks like there is plenty of info there, but pretty much none in a language I can understand.<br />
Looks like it's a good time to start learning Chinese, after all, I wish they taught me that instead of Latin back when I was young!<br />
Now I already speak 3 languages (plus I can curse in Latin too, does that count as a 4th?) and about learning a 4th which has a complex and completely new (to me) alphabet... call me lazy, but, seriously, I am already trying to learn FPGAs, I might pass on this one!<br />
<br />
Finally, scavenging in the discs and renaming folders in a way I can understand them, I found a lot of useful material.<br />
Verilog is Verilog, schematics are schematics and to be fair there are very few times when I found comments that were decent enough to be somewhat useful, so, no big deal if they are written in Chinese after all!<br />
<br />
Verilog modules and variables in the examples are in English, plus you get a separate folder with a full Quartus II project for each experiment.<br />
<br />
I already tried most of the experiments and started to modify a few of them.<br />
Particularly I focused on the VGA interface, which -at least on this board- is not really suitable for a practical purpose.<br />
The signal appears not to be clean enough (might require some proper shielding) and the color depth is only 3 bit (1 bit per color component).<br />
On top of that the voltage I get for each color component seems to be too low, so, what you would expect to be a white pixel (111) turns out to be a pale grey.<br />
Maybe toying around with the IO bank settings on the Cyclone IV could solve that last issue.<br />
That said, all is completely fine to run experiments and learning from them.<br />
I will write another post about VGA, here a picture of a binary color pattern I did yesterday (is it a form of art? :) )<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ5vX6vJI5I-t-c9jYL7s6o-kIOxcvcTiop33oBWnJisgOBhDvgcSPWl7ukxNp4-z36ri_VjISGM54ieXm5mVFbI8Ub4DhEOZfXYjXb5La-itJBiiDWwrnErOkNcIKMYY99bIPkgOEYLQ/s1600/IMG_4328.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ5vX6vJI5I-t-c9jYL7s6o-kIOxcvcTiop33oBWnJisgOBhDvgcSPWl7ukxNp4-z36ri_VjISGM54ieXm5mVFbI8Ub4DhEOZfXYjXb5La-itJBiiDWwrnErOkNcIKMYY99bIPkgOEYLQ/s1600/IMG_4328.JPG" height="300" width="400" /></a></div>
<br />
Meh, I know, kinda useless, right?<br />
That's why I call it art!<br />
Seriously that kind of experiment makes you realize how a VGA sync module works, how to interface with it etc and from a dev perspective, with FPGAs, the color depth does not change much your design.Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-21080841629389635532014-08-17T12:47:00.000+02:002014-08-17T12:47:43.153+02:00Arduino Robot - Putting it togetherThe time of putting (almost) all together finally came.<br />
My young student Marco came over to my place with his family for a week, I showed them around a bit and sure enough we spared quite some time to assemble the robot.<br />
<br />
We did not complete the task, as it was never the plan, but we reached a point where Marco can take over and finish almost autonomously (with my remote support) as a "deeper" learning experience<i>.</i><br />
<i><br /></i>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkgm6_gAMccTqEvyC4qiVfeyqfVzTOUz9R97Us-fbxvvYxu4NswRk7Brb2sp8CWrcGx2MU_c_zlA4kATHpyvapB7RWgaUtMpMHaZu2MhytO-SRxozR_kP2Qll-zuOdfEshhi2jW0Z4ybA/s1600/installing+stepper.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><i><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkgm6_gAMccTqEvyC4qiVfeyqfVzTOUz9R97Us-fbxvvYxu4NswRk7Brb2sp8CWrcGx2MU_c_zlA4kATHpyvapB7RWgaUtMpMHaZu2MhytO-SRxozR_kP2Qll-zuOdfEshhi2jW0Z4ybA/s1600/installing+stepper.png" height="400" width="640" /></i></a></div>
<div style="text-align: center;">
<i><span style="font-size: x-small;">(In the picture Marco installing the stepper motor </span></i></div>
<div style="text-align: center;">
<i><span style="font-size: x-small;">that moves the scanning ultrasound sensor)</span></i></div>
<i><br /></i>
At this point the rover can move a specific amount of centimeters in each direction (using feedback from the encoders), we tested the ultrasound sensors and plenty of functionality is already included in the software (3 different turn types are implemented : on the spot, sharp, shallow, plus motor speed balancing is implemented, coordinate management etc..).<br />
Separately the NRF24L01+ radio system is connected to another arduino pro and an I2C based communication protocol is drafted (and tested) to communicate with the arduino driving the motors+sensors and with other I2C devices.<br />
Also a UART protocol is used to communicate between the PC and the "base" radio station, the PC software is in Java.<br />
<br />
Over time I will help Marco discovering the different parts he likes and activate them.<br />
<br />
Meanwhile I would like to share with you a few lessons learnt from this exercise :<br />
<br />
<b>1) Cables!</b><br />
Okay, we decided to pack a lot of features in this project, so we had to support them with software... but that was not the hard part.<br />
All the devices must be somehow connected with data and power lines and this quickly generates a mess with the cables.<br />
I wanted this specific project done in a way that things could easily be attached and detached, so I had to use a lot of improvised connectors and "flying" cables.<br />
As a general rule, maybe for a more "permanent" project, you may want to secure down your cables to the chassis as much as possible.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWJSlm9ECsKFvmY3Gnw_CO7fnmGO1O2_e2IGNy01pm4NvCvBJD9q0eaJXmxwqcSkMlceN-df7mp0GPVnMPmLsvd8uQsHMAXDYKEXXc3dMgRcdcl_OpyQOeau6ocdSLCCtyidbklwc0bFY/s1600/vcc.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWJSlm9ECsKFvmY3Gnw_CO7fnmGO1O2_e2IGNy01pm4NvCvBJD9q0eaJXmxwqcSkMlceN-df7mp0GPVnMPmLsvd8uQsHMAXDYKEXXc3dMgRcdcl_OpyQOeau6ocdSLCCtyidbklwc0bFY/s1600/vcc.png" height="476" width="640" /></a></div>
<br />
We used a female connector to provide 5V+ground connections to the devices connected on the bottom of the rover : 3 Ultrasound Sensors, Stepper Motor, Hall effect sensor, 2 Encoders.<br />
Only for these power connections 14 wires are floating around!<br />
We use velcro to keep them from getting in the way of wheels etc.<br />
We took the +5V rail out of the motor driver as it contains a 5V LDO regulator (motors are powered @6V, the logic on the H-Bridge driver runs at 5V, hence the internal regulator).<br />
<br />
<b>2) Encoders</b><br />
Encoders are simple right? what could possibly go wrong with them?<br />
Well... turns out you should consider a few things when using them.<br />
I got ourselves a few optocouplers, I carefully checked they were "slotted" (those that are U shaped, emitter on one side, photo-transistor on the other side) and the spacing of the U was ok with the thickness of my encoder wheels.<br />
At least I got that part right :)<br />
Then I started to test those couplers and with my surprise they did not work as expected.<br />
There are several issues, the main one being that when light hits the phototransistor, it's base is activated, but the internal resistance does not go down to zero.<br />
Big deal you may think, something you might also expect, no?<br />
Sure, makes sense, but the issue is that that forms a voltage divider with the pull down resistor you have to add and as a result of that the "high" level is way lower than 5V.<br />
In my case it was around 2V, while the low level was sitting roughly at 1.3-1.7V.<br />
<br />
Direct result of this is that you are not likely going to feed this output directly to an Arduino digital input and in fact I have seen in the web people using an analog input instead and configuring via software the analog threshold to properly detect the logic level.<br />
While that can be a solution, it prevents the usage of interrupts (which are available on digital inputs).<br />
For this reason, some small circuits are sold, containing the coupler, a comparator, the needed resistors and even two fancy tiny leds (pwr-on and logic level).<br />
These circuits make things way easier : simply provide +5V, GND and read a 5V clean logic signal back.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKmiDZNrkX85-mw70FWMaQnBoXHTYSeV19SV54Py5stsF-FMuXsTiVttN4rsh_VTZhnj4qoAhswpKHDTi4pZBsc5hivABxOfI4XOF2zNDj27ZFJP6W2uvb3wkLVEp3wswcJ_UR7s44oU0/s1600/encoder.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKmiDZNrkX85-mw70FWMaQnBoXHTYSeV19SV54Py5stsF-FMuXsTiVttN4rsh_VTZhnj4qoAhswpKHDTi4pZBsc5hivABxOfI4XOF2zNDj27ZFJP6W2uvb3wkLVEp3wswcJ_UR7s44oU0/s1600/encoder.png" height="223" width="320" /></a></div>
<div style="text-align: center;">
<i>(encoder board with comparator, installed on top of the encoder wheel)</i> </div>
<br />
You might avoid them if you are using an MCU that has embedded comparators, else I strongly suggest you buy these little boards as they save you a lot of trouble.<br />
<br />
A final issue with photocouplers is that they are sensitive to ambient light.<br />
That turned out to be a no-problem once installed on the rover as in that position they receive a limited amount of external light, however it polluted my tests when I was trying them on the bench.<br />
No big deal, but something you should account for,<br />
<br />
Also I found not particularly smart that the boards I received had male connectors soldered on the same side of the coupler, that forced me to cut slots in the rover chassis and hook the device from behind it.<br />
And yes, I checked if it was worth de-soldering them and re-soldering them on the opposite side, unfortunately the copper layer on the printed board is so thin that if you get anywhere near with a solder iron, you better know very well what you are doing.<br />
<br />
<b>3) Arduino interrupts</b><br />
Normal arduino boards (uno, pro etc) allow you to use two hardware interrupts on digital pins 2 and 3.<br />
That seemed good enough for me as we only had two encoders.<br />
I am not sure yet about this and I am planning to run some specific tests, but I had the impression that servicing the two interrupts with two different dedicated ISR and having them possibly triggering at the same time <b><u>might</u></b> result in missed interrupts.<br />
At this point I cannot claim that arduino misses interrupts and since I did not check how the ATMega MCU itself manages interrupts I am not aware if this is actually possible... however I noticed some strange behavior, particularly when debugging via serial port at the same time (it might be due to timing).<br />
This is one of the times when I wish I had a NVIC available like in the Stellaris/Tiva series.<br />
<br />
<b>4) Cheap motors</b><br />
There are available in kits and on ebay cheap DC motors, they run at 6V, do not require a lot of current, contain a reduction gear and they are normally provided with wheel and encoder wheel.<br />
To be honest, they are really cool, but their connections are extremely fragile.<br />
It is ok when they are locked in place and you are not shuffling them around, but if occasionally the connection wires you soldered to them get tight... this may easily rip apart the connections.<br />
That happened to us and we had to dismount one of the motors and solder a new wire almost directly on the brush.<br />
Unless you practice Zen frequently, I strongly suggest you try to avoid that.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisbPcdPFSBODLTjX8ka1M_LhBB7bKMHRh_OZAP_hSr480Hws5UIe_9ul74qMNlsfq6y6UOEIkIK81tol994IstI0q114jYvLnQOMo6Wu50dl5JlJe0lKurLUKqY2pZ0oOfzBLkIwE-zOo/s1600/tail.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisbPcdPFSBODLTjX8ka1M_LhBB7bKMHRh_OZAP_hSr480Hws5UIe_9ul74qMNlsfq6y6UOEIkIK81tol994IstI0q114jYvLnQOMo6Wu50dl5JlJe0lKurLUKqY2pZ0oOfzBLkIwE-zOo/s1600/tail.jpg" height="506" width="640" /></a></div>
<div style="text-align: center;">
<i><span style="font-size: x-small;">(Installing the tail wheel)</span></i></div>
<br />
Overall it was a real fun experience, as it always is when playing with Arduino.<br />
It is amazing how easy is to explain technology to an enthusiastic and smart 10 year old using Arduino, I really believe it is a perfect platform for this task.<br />
I personally prefer to have a bit more control over the hardware, but that comes with some more complexity, which definitely adds to the fun once you can grasp the basics, until then : Arduino all the way :)<br />
<br />
Aside from the main robot activity I was able to help Marco learn how to solder, about serial protocols (I2C, SPI...), how to use a drill press, how to use a multimeter and read an oscilloscope.<br />
<br />
There is a new geek in town! :)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXoTz58UzDfBiqlwAjLYgbGXuDjNGGTkoBpkfMQEZiVjKy8-sZXoWMKG4GCItVdZMk9kLHlNUANd_eVUmFsbwHNVVkOQNohYK9UGj4__WupCLhiKNn7-bP_VOVce4Xp07LJbJeiECGk6Y/s1600/pressdrill.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXoTz58UzDfBiqlwAjLYgbGXuDjNGGTkoBpkfMQEZiVjKy8-sZXoWMKG4GCItVdZMk9kLHlNUANd_eVUmFsbwHNVVkOQNohYK9UGj4__WupCLhiKNn7-bP_VOVce4Xp07LJbJeiECGk6Y/s1600/pressdrill.jpg" height="440" width="640" /></a></div>
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-4123531706198698512014-06-23T11:47:00.002+02:002014-06-23T11:47:23.556+02:00Arduino Robot - LiPo batteries updateI said (<a href="http://fortytwoandnow.blogspot.ch/2014/06/arduino-robot-psu.html" target="_blank">here</a>) I did not know much about LiPo battery output and their maximum discharge rate.<br />
<div>
I made a few assumptions and simply said that my 1200mAh 25C should have been more than fine (<a href="http://fortytwoandnow.blogspot.ch/2014/05/arduino-robot.html" target="_blank">for this project</a>) since if it could power an RC car/helicopter, then it should have been more than enough for my two small DC motors and few other digital electronics.<br />
<br />
Still, it was a good opportunity to understand some more and I researched the meaning of that "25C", here the results :<br />
<br />
When you have a battery pack that is declared at xxx mAh you actually know the maximum charge that can be stored in it, but that does not tell you how fast you can (safely, possibly) discharge it or in other words, how many Amperes of current you can draw from it.<br />
1200mAh means that if you draw 1200mA continuously, a completely charged battery will be depleted in 1 hour (assuming you can pull all the charge, which is quite unlikely due to voltage drop that goes with it, plus it is advisable to pull only 80% max of the battery charge to prolong its life).<br />
<div>
That does not leave any clue on how you can use that charge, is it going to be at 10mA at a time, at 10A or else?</div>
<br />
That's where the "C" rating comes into place for LiPo batteries.<br />
From what I found the C coefficient has to be multiplied by the total charge of your battery (1200mAh in my case) and that gives the maximum (peak) Amps you can draw.<br />
Now, a bit of math tells us that a 1200mAh @25C can output a whopping 30Amps peak.. at least in theory.<br />
Honestly I don't really think that figure is anywhere near a realistic one, 30A is a scary amount of current even at the moderate voltage we are dealing with (average 7.4V, up to 8.something).<br />
We are talking about 220Watts of energy (7.4 * 30)!<br />
Granted at 30A you would drain the fully charged battery in only 2.4 minutes (1.200/30.000*60)... but I still believe that 30A * 7.4V for two continuous minutes are still a serious business.<br />
I initially thought I had it all wrong, but searching on the web it seems these are the correct figures (!!!).<br />
One of the sources <a href="http://rcfoamfighters.com/blog/?p=84" target="_blank">here</a>.<br />
<br />
However, when I look at those small wires coming out of it, I see something that seems to have pretty good quality, but still I hardly see them carrying 30Amps without transforming suddenly in a smelly ball of smoke.<br />
I would not feel really safe exceeding 5A, which again is about 10x more than I need.<br />
<br />
In conclusion : The max current seems more than adequate for my purpose, all hail to the magic of LiPo batteries... yes but...<br />
Right, is this all so cool, no flipside?<br />
Well, it is until you happen to short circuit your battery, in that case I fear the best thing that can happen is a bit of smoke, fire if it was not your lucky day and a nice "kaboom" if your horoscope that day was not favorable (in that case you probably deserve it, at least for believing in horoscopes!).<br />
With big power comes big responsibility, play it safe! </div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-61994742036032043332014-06-16T22:06:00.002+02:002014-06-16T22:07:03.669+02:00Arduino Robot - "Zeroing" Stepper motors Hello, this is yet another post related to the series dedicated to the <a href="http://fortytwoandnow.blogspot.ch/2014/05/arduino-robot.html" target="_blank">Arduino Rover project</a>.<br />
These posts, although eventually enjoyable by any kind of maker, are targeted to young and non particularly expert geeks.<br />
Not long ago I was <a href="http://fortytwoandnow.blogspot.ch/2014/05/arduino-robot-hall-effect-sensors.html" target="_blank">toying around with hall effect sensors</a>, the reason I was is related to today's posts.<br />
<br />
The rover will have <a href="http://fortytwoandnow.blogspot.ch/2014/05/arduino-robot-ultrasound-sensor.html" target="_blank">three ultrasound sensors</a> (yup, 3!!! they are cheap :) ) in the front side.<br />
Two of them will point slightly on the side (one per each side, symmetrically) and the central one normally will point straight ahead.<br />
This one will be mounted on <a href="http://fortytwoandnow.blogspot.ch/2014/04/stellaris-launchpad-stepper-motors.html" target="_blank">a stepper motor </a>which will allow the rover to scan the area in front of it (and eventually map it, sending back sonar data via the NRF24L01+ radio). <br />
To avoid ultrasonic interference the three modules will be triggered separately (the two side ones will be on the same trigger, sensors have a 15 degree angle sensitivity, they will be pointing in directions that are way more than that angle apart).<br />
<br />
Stepper motors, particularly the one I chose (a cheap <a href="http://fortytwoandnow.blogspot.ch/2014/04/stellaris-launchpad-stepper-motors.html" target="_blank">28bjy-48</a>, with gearbox reduction), can have a very fine resolution, so they can provide a very precise scanning, way more than the 15deg sensitivity angle of the ultrasound sensor... gotta do something about that, probably via software.<br />
<br />
Despite the fact they can rotate an extremely precise amount of degrees, unfortunately they cannot remember their position, it is normally up to the software to keep track of it.<br />
But what happens if you reset the MCU running such piece of software while the motor is in a given position X?<br />
It happens that whatever variable you were using -if not stored in some flash memory or similar solution- it will be re-initialized at boot time after the reset.<br />
<br />
Sure, saving this variable in a non volatile storage might help... but still might fall short of other issues, such as a motor "missing" a few steps.<br />
Actually you instruct the motor to move X steps, but you have no feedback if it actually moved that precise number of steps.<br />
It normally does, unless it gets stuck against something.<br />
<br />
So a good solution is to detect a zero position and reset your position variable on that at each boot or even from time to time during normal operation.<br />
<br />
Then the question becomes :how to?<br />
As we said, a stepper motor provides no feedback, so we need to ADD something that does.<br />
A typical solution is to use a magnetic or optical device, basically something static that can detect a moving part without touching it.<br />
<br />
I went for the magnetic solution, using a hall effect sensor and neodymium magnets.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0RzFJoBtwJDTWINzQjabEGqqWlQu-252dCQUGnty-7LpnZ0vhpp9vfix5fVBXmDaJW0P9fYq6oO_WTsKbWOeLrEc6TuZ8FWtSetiFy38ALoY1nL5xjswXJeWoIpr2V7_Aoc4MhswYrY8/s1600/hallstep1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0RzFJoBtwJDTWINzQjabEGqqWlQu-252dCQUGnty-7LpnZ0vhpp9vfix5fVBXmDaJW0P9fYq6oO_WTsKbWOeLrEc6TuZ8FWtSetiFy38ALoY1nL5xjswXJeWoIpr2V7_Aoc4MhswYrY8/s1600/hallstep1.png" height="258" width="400" /></a></div>
<br />
The one in the picture is just a test setup, as you can see the small hall effect sensor is taped down while the final solution will hopefully be a bit more stable.<br />
The stepper motor is physically on the opposite side, below the wooden surface, and a 2mm thick piece of plastic is connected to its shaft, coming this side of the chassis.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbxqdSRtKiqde0ONBDu5snzZz4GEu325omB9A08LZkOqGm-tTkmgCVE0-GX1bGYkgbbZoOf7Io9385NK7mARuUo3vfnFFhWFgVAvStv_TlXG3e6bFqkXj_VVcY4Z5Gwp5jr-ZMVP-0SDc/s1600/rover_hall.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbxqdSRtKiqde0ONBDu5snzZz4GEu325omB9A08LZkOqGm-tTkmgCVE0-GX1bGYkgbbZoOf7Io9385NK7mARuUo3vfnFFhWFgVAvStv_TlXG3e6bFqkXj_VVcY4Z5Gwp5jr-ZMVP-0SDc/s1600/rover_hall.jpg" height="300" width="400" /></a></div>
<br />
<br />
I am using some tiny round neodymium magnets (got 200 of those, also really cheap on ebay), they are 3mm in diameter and 1 mm thick, so I was able to embed 2 of them in the 2mm thick plastic.<br />
I simply drilled a 2.8mm hole with my dremel, they are slightly forced in, no need for glue or anything else, they just stay there nicely.<br />
<br />
I connected motor and sensor to the arduino, using a mega for this test, a Uno or pro mini would do the same, I just had this one available at the moment and did not want to disconnect the others I am using for other purposes.<br />
<br />
Then using the Stepper Library demo code (configured to run with the mega pins)<br />
I managed to have the motor turn clockwise for a few steps and counter-clockwise for the same number of steps, continuously.<br />
The LED is turned on if the digital pin connected to the sensor is LOW (sensor is active LOW).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/6n7iP1lX4p8?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
The key thing is that I move the motor 1 step at a time and at each step I poll the sensor (you could theoretically use interrupts for this, but I will need two interrupts for the speed encoders and arduino does not have any spare int available :( ).<br />
<br />
Now that we saw it works, we need to consider that, even if those magnets are really small -and you might find smaller ones, but they become more difficult to handle- they still cover an area that is represented by a finite number of steps.<br />
Arguably this area might change <u>a bit</u> depending on the distance (the radius) at which you place them from the shaft.<br />
<br />
The idea is to consider as ZERO the position of the stepper motor that corresponds to the center of the magnet being over the center of the sensor.<br />
We then need to calculate, when the magnet hits the sensor, how many steps it needs to clear it again.<br />
<br />
My simple code is here :<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#include <Stepper.h></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int input_pin = 52;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int sensor_vcc =50;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int led_pin = 13;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int cnt=0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int dir =-1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int lastSensor = LOW;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">// initialize the stepper library </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">// I am using a MEGA!!</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Stepper myStepper(stepsPerRevolution, 30,26,28,24); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void setup()</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> Serial.begin(9600);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> pinMode(led_pin,OUTPUT);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> pinMode(input_pin,INPUT_PULLUP);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> pinMode(sensor_vcc,OUTPUT);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> digitalWrite(sensor_vcc,HIGH); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> digitalWrite(led_pin,LOW); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> myStepper.setSpeed(40);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void loop()</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if (digitalRead(input_pin)==LOW)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //detecting magnet</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if (lastSensor==LOW)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> cnt=0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> lastSensor=HIGH;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> cnt++;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> } else </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if (lastSensor==HIGH) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> Serial.println(cnt);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> lastSensor= LOW;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> myStepper.step(dir); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<div>
<br /></div>
Turns out that the readings are quite consistent and it usually takes 36 steps with that sensor, placed in that position, with those magnets etc... you need to run your own measurements if you try to replicate this experiment.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEiVwfnqpbf0mJ0hWYj_c5olkfHYV9ADfh3S6945jNJGnxyNynb05PLO0Cauv5iazchQJJh3jXI37hCMVsbVP9pUMhdCa5SLeKOkBjUTDTT9QGAfWh8Iqkl0CblkEauxwkWPl0ywVOjTw/s1600/hall_magnet.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEiVwfnqpbf0mJ0hWYj_c5olkfHYV9ADfh3S6945jNJGnxyNynb05PLO0Cauv5iazchQJJh3jXI37hCMVsbVP9pUMhdCa5SLeKOkBjUTDTT9QGAfWh8Iqkl0CblkEauxwkWPl0ywVOjTw/s1600/hall_magnet.png" height="400" width="375" /></a></div>
<br />
<br />
You probably noticed that the numbers tend to increase after few passes, that happened because the tape started to warp a bit when heated by the lamp and the sensor raised a bit getting closer to the magnet.<br />
As I pressed it down again it temporarily went back to 37, this will not happen when the sensor is securely placed on the rover.<br />
As a general rule, when you zero your motor at boot or anytime you may need it, you should also check again this number of steps and get half the value as the zero position.Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com2tag:blogger.com,1999:blog-3747970306027691432.post-46633569814548250092014-06-11T10:16:00.000+02:002014-06-11T19:58:13.623+02:00Arduino Robot - PSU<div class="separator" style="clear: both; text-align: center;">
</div>
The <a href="http://fortytwoandnow.blogspot.com/2014/05/arduino-robot.html" target="_blank">Rover</a> is supposed to have plenty of devices on it, it will have a couple of arduino's (maybe 3), several sensors, two dc motors, a stepper motor, a radio...<br />
<br />
That calls for some energy!<br />
The easy solution would be to use the 4xAA battery holder provided with the kit, but there are a few reasons this could be a bit less than optimal :<br />
<br />
1) If we plan to use rechargeable batteries, the output would be 4x1.2V = 4.8V which is probably enough to run the 5V arduinos, but a bit weak for the dc motors (they give you full power at 6V).<br />
<br />
2) The battery holder consumes a bit of space and the pack will weight a bit<br />
<br />
3) As the provided voltage is already quite low, when batteries discharge this will drop further to a level that is not sufficient to power the devices, limiting our ability to fully use the energy stored in the batteries.<br />
<br />
I thought a better solution would have been a LiPO battery, a two cells one gives an average 7.4V which is high enough for the motors, the arduinos etc, leaving enough room for voltage drop.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyGhnAZ6qu2f0sjKEC2Rg_QG4vs5yRp4egFVImOFDRGowDEpvOfaDrpHsqMOGcGDG6gDeAUDARg6zQKtPjSqIMrfJXIAMu1V4mOZrsejtZFjoSfa-Jb7wJQbPTUlxQE8zxyT2SNnLYiMQ/s1600/batteria.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyGhnAZ6qu2f0sjKEC2Rg_QG4vs5yRp4egFVImOFDRGowDEpvOfaDrpHsqMOGcGDG6gDeAUDARg6zQKtPjSqIMrfJXIAMu1V4mOZrsejtZFjoSfa-Jb7wJQbPTUlxQE8zxyT2SNnLYiMQ/s1600/batteria.png" height="198" width="320" /></a></div>
<br />
You can easily find batteries like this one on ebay, I am no expert with these, but some common sense reasoning helps in making sure the one you select is ok for your project :<br />
1) The only energy hungry parts in the rover are the two DC motors, they need 6V and can sink a limited amount of current. I found some data, but not really sure about it since no part number was mentioned, some sources say the max current could be 250mA per motor, most of the sources say it is way less... I assumed 250mA to be conservative<br />
2) Most RC models have non geared and power hungry dc motors, so , whatever battery that works for them will do just fine with the motors we have. To be on the safe side I purchased a 25C (high discharge rate)<br />
3) 1200mAH is not much, but comparable to the charge of NiCd rechargeable AA batteries, with the benefit that the higher voltage will allow us to better use the charge.<br />
<br />
So, I went for a 1200mAH, 25C 2 cells (7.4V) LiPo battery, and got a balanced charger for it.<br />
<br />
Probably I could feed the Motors directly from the battery, but again to play it safe and have a predictable result I decided to step down the voltage to about 6V for them.<br />
<br />
We know there are different options to step down DC voltages, at least 3 come to my mind :<br />
1) Use a linear voltage regulator (probably the most common)<br />
2) Use a buck converter<br />
3) Use the drop voltage of (a series of) diodes<br />
<br />
Linear voltage regulators are pretty handy, easy to use, they provide a clean output, but they are normally not efficient.<br />
Here we are dealing with motors, no need for a clean power supply, but conversion efficiency might be important, so buck converters become a good option.<br />
Diode drop voltage is not suitable because of efficiency, and does not regulate the output, it simply reduces the input voltage of a given amount of volts (usually 0.6V per diode).<br />
<br />
So, I got myself a nice buck converter, they can be sourced really cheap now so they are becoming a good alternative for DC regulation , at least when you want to exceed 1 Amp.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheueAWepac6Fwj-yMh3Zqoryr3DZky11ZfSjGfwV44ASpOKnr2W7zaa1jBocR_bOFDMMv_it88TVGSrJsAXfmEQf-tFzi0PQhnsbdwXofsGkVBF6GTcdraeWF6xa6ogpkKECEE8k1d37I/s1600/buck.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheueAWepac6Fwj-yMh3Zqoryr3DZky11ZfSjGfwV44ASpOKnr2W7zaa1jBocR_bOFDMMv_it88TVGSrJsAXfmEQf-tFzi0PQhnsbdwXofsGkVBF6GTcdraeWF6xa6ogpkKECEE8k1d37I/s1600/buck.png" height="262" width="320" /></a></div>
<br />
Less than 2$ shipped, 3Amp maximum (leaves room for eventual future upgrades) and a wide range input/ output with a max 92% conversion efficiency (advertised).<br />
Not too bad.<br />
<br />
The problem with linear regulators is that the difference between the input and the output voltage is obtained mostly by dissipating energy as heat, therefore their conversion efficiency is pretty low.<br />
If you have a power hungry device then efficiency becomes relevant, in fact if I have to supply only 100mA,5V and I have a 50% efficiency, I am wasting 5*0.1 W =0.5Watts of energy.<br />
Now, if we had the same efficiency with a 3000mA output, then the wasted energy would have been 5*3 = 15W !! which also requires proper heat dissipation.<br />
<br />
That said, we still need to power the arduinos and the other connected devices... here we definitely need a clean power source, and the power consumption is going to be pretty low, so linear regulators are a good option.<br />
<br />
I selected to use the arduino pro mini because it is really small, cheap and provides the same features as the Uno board... well, almost.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiCPzOD_CcrEsO8Wlff_oA_GKucNOiUV3zW9Px3Suzlmg342AM_2naHKnnLt-QMbZpH69AW6D7bep91t4pYvA4MXPs28YBnF6We3msXgOpwBXJWfDwMFyOWIY4tOis2vM3OMsgbBMHT28/s1600/images.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiCPzOD_CcrEsO8Wlff_oA_GKucNOiUV3zW9Px3Suzlmg342AM_2naHKnnLt-QMbZpH69AW6D7bep91t4pYvA4MXPs28YBnF6We3msXgOpwBXJWfDwMFyOWIY4tOis2vM3OMsgbBMHT28/s1600/images.jpg" /></a></div>
<br />
The first thing to consider is that these boards are available at different voltages (3.3V and 5V) and different frequencies (8MHz and 16MHz).<br />
I went for a 5V 16MHz one.<br />
Second thing to know is that they do not include and FTDI interface like the Uno, so if you want to program them you need one external (I have a few always floating around on my desk, normally :) ).<br />
<br />
The other important thing is that they do include a voltage regulator (the tiny chip on the middle-left part of the picture), so that you can feed them a non regulated input (5V to 16V)....<br />
BUT the Uno contains a secondary regulator providing 3.3V supply for sensors and whatever you need to power at 3.3V, the pro mini does not have such secondary regulator.<br />
<br />
We need 3.3V for the radio, the compass and other sensors... so that will be provided by our PSU board via another linear voltage regulator.<br />
To be fair, here the internal voltage drop of the diodes would have been a decent solution : the input could have been the 5V regulated VCC from the Arduino pro, the current needed is few milliAmps, so 3 diodes in series would provide a 1.8V drop -> 5-1.8 = 3.2V,. good enough for our 3.3V supply.<br />
<br />
I just preferred to integrate this in the PSU board, but realized I ran out of 3.3V regulators (actually I do have some SMD ones, but they would be a pain to be soldered to the proto board) so I went for a variable regulator, the famous LM317 (you should always have a few around).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs1sziLPgc6LrRcRagjp-CznSWz6hZIfSJoY18QGV-WbMcHoGFxJNm_2BhKIqB0FXpmKOsAVV5Wb2YBY6UyawvTTcNiMhONnmDwE-rPggRLpgt5cUYAgwpkRi1n58Q_cKYtoFlY2hRzI8/s1600/lm317.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs1sziLPgc6LrRcRagjp-CznSWz6hZIfSJoY18QGV-WbMcHoGFxJNm_2BhKIqB0FXpmKOsAVV5Wb2YBY6UyawvTTcNiMhONnmDwE-rPggRLpgt5cUYAgwpkRi1n58Q_cKYtoFlY2hRzI8/s1600/lm317.jpg" /></a></div>
<br />
<br />
Turns out it was not a good idea, let me explain why.<br />
The LM317 is fairly easy to use, quite versatile, has a poor efficiency (but since we need few mA it would do) and can provide up to 1.5A output if mounted on a heat sink.<br />
Way more than we need, right?<br />
Nope, sometimes it is better to get "just what you need".<br />
Turns out that I always disregarded one of the characteristics of this extremely useful device : it does not work if the load is less than 10mA.<br />
Once I configured the circuit placing proper R1 and R2 (V = 1.25(1+(R2/R1))) I had no load and I was measuring the voltage, discovering it was ranging from 2.3V to 4.8V, oscillating in an unpredictable way.<br />
<br />
Now, the radio will sink up to 14mA when transmitting, this would give us enough load, but when not transmitting the sum of all the 3.3V devices connected will be less than 10mA.<br />
<br />
I temporarily patched the circuit adding a 330Ohm resistor in parallel to the load, that works but it is a sub-optimal solution as I am now constantly wasting 10mA of energy on the 3.3V rail!<br />
It will have to do until the 3.3V regulators I ordered (got some 100mA ones) arrive.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhepjSoiymkU1D8Nj_rvOW8lsDkZw5lRUSzJDF20peRWOF6f2bromvtJco8Mwtaps6_pXcvZirngpbQlQT8pUCiyYrvrgy-_g71ZBtpSX6mLw2XlB75xDJPoIOjtryuPMtmw3wJu46VlN8/s1600/psu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhepjSoiymkU1D8Nj_rvOW8lsDkZw5lRUSzJDF20peRWOF6f2bromvtJco8Mwtaps6_pXcvZirngpbQlQT8pUCiyYrvrgy-_g71ZBtpSX6mLw2XlB75xDJPoIOjtryuPMtmw3wJu46VlN8/s1600/psu.png" height="248" width="400" /></a></div>
<br />
<br />
On the proto board I soldered all the different parts, added an LED for every rail (battery, motor, 3.3v), some pins to connect directly the 3.3V devices etc.<br />
<br />
The board itself is mounted with spacers and is protected with a rubber-ish sheet that also provides enough pressure to hold the battery in place.<br />
The battery slides below the board.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3MwK8gGENreg9R1eQyhwmPLM8s7BUbxn0R4jzcgbhPT1vFEPgVvuZF3i5w32CMCgHHZJVuNJoI7AJgdUVNBoHmjB-yL3QL2hKGmX3L9M952kqYo9GrzXFVWH7eJsiYW4mQOhMPNPu41E/s1600/batt.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3MwK8gGENreg9R1eQyhwmPLM8s7BUbxn0R4jzcgbhPT1vFEPgVvuZF3i5w32CMCgHHZJVuNJoI7AJgdUVNBoHmjB-yL3QL2hKGmX3L9M952kqYo9GrzXFVWH7eJsiYW4mQOhMPNPu41E/s1600/batt.jpg" height="268" width="400" /></a></div>
<br />
(Note, it is all mounted on top of some wooden temporary chassis which I am using to study the optimal position of the various parts before drilling -or better let my young student drill- holes in the final one).<br />
<br />
Another feature I wanted to add is the ability to monitor the voltages of the 3 rails, in order to detect when the battery is discharging or if one of the regulators is malfunctioning/ not properly configured.<br />
<br />
To achieve that the Arduino's ADC is going to help, however some precautions must be taken.<br />
<br />
The maximum voltages on the 3 rails are : 8.5V (maximum voltage of the battery), 8.5V (itf the buck converts 1:1) and 4.5V (if the 3.3V regulator is off).<br />
<br />
The 5V arduino can accept maximum 5V on its ADC, exceeding this limit might actually burn it (and no, we don't want that, right?).<br />
<br />
So, it is rather safe to feed the 3.3V rail to the ADC, but not the other ones, we will add a voltage divider (a couple of resistors, you can google it up if you don't know how it works), dividing by two.<br />
The <b>analogRead</b> function provides a value between 0 and 1023 since the ADC has a 10 bit resolution and, if you do not use an external reference voltage, 1023 corresponds to the Arduino's VCC (roughly 5v).<br />
<br />
Let's say we read <b><i>adcX</i></b> on the pin connected to the 3.3V rail.<br />
We know there is no voltage divider on that one, so 1023 would mean 5V -><br />
<br />
<b><i>adcX</i></b> : V = 1023 : 5<br />
<br />
-> V = <b><i>adcX</i></b> * 5 / 1023 being V the calculated voltage.<br />
<div>
<br /></div>
For the other two rails, we know we have /2 a voltage divider, so 1023 would mean 10V instead of 5.<br />
<br />
-> V = adcX * 10 / 1023<br />
<div>
<br /></div>
<div>
I did fetch the values (I have a second arduino connected to my pc via FTDI serial, it acts as a "serial to radio" bridge with a protocol I implemented for it. The radio connects to the arduino pro on the rover which itnerprets the commands and answers) and noticed they were a bit off.</div>
<div>
<br /></div>
<div>
My multimeter was giving me 3.38V on the 3.3V, while Arduino was returning 3.13V.</div>
<div>
<br /></div>
<div>
This is to be expected and it can be corrected easily.</div>
<div>
What happens here is that the Vcc provided by the regulator on the arduino is not exactly 5V, so the reference for the ADC conversion is not 5V either!</div>
<div>
<br /></div>
<div>
Do we need to know the exact Vcc then?</div>
<div>
No, not necessarily, we can just compute the error between the value reported by the multimeter and the one calculated by arduino.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhssh8V6lUre_aKPhAdaIyL6C98beh8hjxXu5em4Uz_C7I7Sju9TKYrjqlio7XGy2q9Qq7JEH9Mk8tfxIxYR-dfw5uxRqvcdM_PgqufS6ER5esyAt_34g4gfHdn3g-sMJoQhXmqBLEmEeU/s1600/get_voltages.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhssh8V6lUre_aKPhAdaIyL6C98beh8hjxXu5em4Uz_C7I7Sju9TKYrjqlio7XGy2q9Qq7JEH9Mk8tfxIxYR-dfw5uxRqvcdM_PgqufS6ER5esyAt_34g4gfHdn3g-sMJoQhXmqBLEmEeU/s1600/get_voltages.png" height="246" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
The ratio between those two values gives us a correction factor that can be applied to all calculations (in my case it was 1.093).</div>
<div>
Normally you would want to check that ratio with a set of different measurements and eventually consider that as the linear regulator becomes warmer it might drift a bit altering again the ratio.</div>
<div>
There are technical solutions for this, such as adding an external reference, but that exceeds the purpose of this experiment.</div>
<div>
<br /></div>
<div>
Overall, now the rover has a decent power management which includes feedback control, it has an <b>almost </b>reliable radio communication system... </div>
<div>
We are almost ready for Mars... or, well, maybe the backyard (for now) :)</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0tag:blogger.com,1999:blog-3747970306027691432.post-367040930140284772014-05-27T15:03:00.000+02:002014-05-27T15:03:32.971+02:00Arduino Robot - Hall Effect sensorsHall effect sensors are tiny devices that can rapidly sense the presence of a magnetic field.<br />
<br />
This effect was discovered by Edwin Hall back in 1879 and it is based upon the interaction of magnetic fields with electric ones.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/en/7/7c/Edwin_Herbert_Hall_(1855-1938).jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/en/7/7c/Edwin_Herbert_Hall_(1855-1938).jpg" /></a></div>
<div style="text-align: center;">
<i>Edwin Hall (from Wikipedia)</i></div>
<div style="text-align: center;">
<br /></div>
Technically, what a hall effect detector does is to operate as a switch activated by a magnetic field in the proximity.<br />In other words, it is a reliable way to activate a switch between two moving parts, without having them to physically touch.<br />
This turns in handy when you need to detect the rotation speed of an object (i.e. a HDD drive disk) and you don't want to have the moving part and the static one touching (which would lead to friction and eventually wear off the contact after some time).<br />
<br />
When a magnetic field interacts with an electric field (and it is not parallel to it), electrons are subject to a force (Lorentz Force) that makes them alter their path.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4qblNq-T6ncjim3XvcFaY24ttZH54PJvBE_He4Hu6jojZ4vyPbyHQ76uKy4edF2TutIGPtb_8BEgO4X2h3LyeHOGbP7iP6sPsD6eyu1j9chr2NgPX0Wjfy08XF86cEqMISbdJtqP_p1M/s1600/halleff.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4qblNq-T6ncjim3XvcFaY24ttZH54PJvBE_He4Hu6jojZ4vyPbyHQ76uKy4edF2TutIGPtb_8BEgO4X2h3LyeHOGbP7iP6sPsD6eyu1j9chr2NgPX0Wjfy08XF86cEqMISbdJtqP_p1M/s1600/halleff.png" height="368" width="400" /></a></div>
<br />
In step 1 an electric field exists in the conductor, electrons move from left to right.<br />
A non parallel (try to visualize it in 3D, ideally perpendicular to the XY plane) a magnetic field generates a Lorentz Force on the electrons.<br />
In step 2 the Lorentz Force pushes the electrons against the upper border of the conductor generating a polarization - / + on the two edges of the conductor.<br />
In step 3 the polarization difference is measured as a voltage perpendicularly to the conductor.<br />
<br />
Some commercial devices are available to be used directly as digital switches.<br />
I used some A3144E, which can be easily sourced online at relatively low cost (paid less than 2$ for a set of 10, shipped).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQVefJiK5moQ-2JzJVzY92DAqDFy3LwNF63mpa-iVud4rjgbTKsv8ijUkSOlQfxIb4aTJPGEGYsWj-OdSrKglsA6tS3jMg5OC8e8URObHQCMemd4oVWJSVeW3d36l6sAEstSaM6P-F6bw/s1600/a3144e.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQVefJiK5moQ-2JzJVzY92DAqDFy3LwNF63mpa-iVud4rjgbTKsv8ijUkSOlQfxIb4aTJPGEGYsWj-OdSrKglsA6tS3jMg5OC8e8URObHQCMemd4oVWJSVeW3d36l6sAEstSaM6P-F6bw/s1600/a3144e.jpg" height="320" width="320" /></a></div>
<br />
To use them is quite simple, just connect the center pin to GND, the left one (looking at the device you should see the writings on it to make sure you are facing the correct side) to VCC (4.5V up to 28V, it contains a regulator) and the right pin to your digital input.<br />
The output voltage is = Vcc, so be careful if you are planning to use a 3.3V MCU.<br />
<br />
A very basic Arduino sketch to test it :<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int input_pin = 7;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int led_pin = 13;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void setup()</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> pinMode(led_pin,OUTPUT);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> pinMode(input_pin,INPUT_PULLUP);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> digitalWrite(led_pin,LOW); </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">void loop()</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> digitalWrite(led_pin,!digitalRead(input_pin));</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<br />
Notice I enable a pullup resistor on the input, just in case to avoid floating signals.<br />
Another thing you should mind is that this sensor is activated by a magnetic field of a specific polarity, the opposite polarity is activated by the opposite side of the same sensor, make sure you place you magnet correctly.<br />
<br />
The reason why I am testing these sensors is to identify a ZERO point for a stepping motor.<br />
Let me explain better : I will mount a ultrasound sensor on top of a stepping motor, this will enable a fine scanning of the area.<br />
However unfortunately stepping motors do not record or detect their position, so if the sensor is all the way to the left, in the middle or half way to the right, only the software, counting the steps, can tell.<br />
Unfortunately if you reset your MCU the sensor will remain in whatever position it was before the reset and the step count will start from zero.<br />
<br />
So, when booting the MCU I could move the stepping motor until a tiny magnet reaches a hall effect sensor.<br />
Depending on the size of the magnet we can calculate how many steps we will need to clear it, thus we can calculate the mid point giving us a reliable zero reading.<br />
I will probably use two sensors, static and a rotating neodymium magnet (will rotate together with the ultrasound sensor), meaning I will need to travel 180 degrees maximum before hitting one of the two sensors and being able to calculate the exact position.<br />
Hopefully I will be able to show details of the construction once I present the ultrasound scanner, provided I will finally implement it that way :)<br />
<br />
<br />Franzhttp://www.blogger.com/profile/18441386776102308538noreply@blogger.com0