ARM/STM32 comparing 4 pins - Page 1
Forum section: electronics / general

author: mc
author_rank: Regular Contributor
timestamp: October 04, 2014, 05:45:06 pm
content: Essentially what I want to do, is read PB0-3, compare them to a stored value, and if they match set a status flag true.I'll admit I'm pretty hopeless at Bitwise things mainly due to not really having to use them much, however I'm not entirely sure that is the solution to this problem.In the past in Arduino, I would of used something like if(readdata & xxxx1111b), however CoIDE gives an error because of the x's and just doesn't seem to accept binary with any form of suffix/prefix.Swapping to hex or decimal compiles without error, but returns true on 3, 6 or 7.Can somebody point me in the direction I need, as my google skills just aren't throwing up anything helpful?For reference, the full details are I'm using a STM32 Discovery board (STMF100RB), with PB0-7 connected to another controllers 8bit databus, along with Start and Clock pulses on PA1&2. When Start is asserted by the controller, it places an address on PB0-3, along with a command on PB4-7.I need to read the address, and compare it with the programmed address in the STM32.The command part is not implemented at the moment, so I can ignore that for now (I'm interfacing to somebody elses design, so I have no control over that), however it will probably be implemented at some point in the future and I will also need the ability to read and handle that.I'm just currently struggling with how to split the 16bit integer port read into 4 bit pieces.

author: bingo600
author_rank: Super Contributor
timestamp: October 04, 2014, 06:12:58 pm
content: Code:For comparin the 4 low bitsif((portdata & 0x0f) == storeddata)split 16uint16_t val16;uint8_t v1,v2,v3,v4;v4 = ((val16 & 0xf000) >> 12) //bit 15-12 placed at 0..3v3 = ((val16 & 0x0f00) >> 8) //8..11 placed at 0..3v2 = ((val16 & 0x00f0) >> 4) //7..4 placed at 0..3v1 = ((val16 & 0x000f) >> 0) //3..0 placed at 0..3/Bingo

author: andersm
author_rank: Super Contributor
timestamp: October 04, 2014, 06:31:38 pm
content: Quote from: mc on October 04, 2014, 05:45:06 pmBinary literals are not part of C. Check your compiler documentation if it supports them as an extension. They were added to C++14, so I imagine they will be added to C in the next standard revision.

author: bingo600
author_rank: Super Contributor
timestamp: October 04, 2014, 06:34:18 pm
content: Afaik the 'b postfix (binary type) was added to avr-gcc back in 3.xxx (as a "hack")But not those xxx'es.Dooh- This is arm-none-eabi i guess./Bingo

author: bobcat
author_rank: Regular Contributor
timestamp: October 04, 2014, 06:53:20 pm
content: gcc will accept 0b as a binary prefix. So, you might try 0b00001111 for your compare mask.

author: dannyf
author_rank: Super Contributor
timestamp: October 04, 2014, 07:03:19 pm
content: QuoteThat's not possible, unless you have a private development environment for your arduino.It is fairly simple:Code:if (myvar == (PORT & 0x0f)) do_something();PORT is the port where you want to read the lowest 4 bits.

author: mc
author_rank: Regular Contributor
timestamp: October 04, 2014, 07:26:59 pm
content: Thanks for the replies.It turns out the actual problem is the STM32 is too slow for this application, so by the time I enter the interrupt and get to reading the address, the address is already gone and actual data is on the bus.I've attached a screengrab of what's happening.I just tried a minimal interupt on the Start line, with maximum priority, and the time taken for the interrupt to simply turn on a pin/led (D5 in the grab) is ~3uS. That's without trying to grab and compare addresses.I knew this project was going to push timing, however I didn't think it would push it quite that far!

author: dannyf
author_rank: Super Contributor
timestamp: October 04, 2014, 07:42:18 pm
content: QuoteI have had that happening to me with bus drivers with a lead foot.I think a speed governor would have helped in those cases.

author: mc
author_rank: Regular Contributor
timestamp: October 04, 2014, 08:03:34 pm
content: I've just realised that all the Discovery boards I have are 8MHz, however I'm not sure if throwing more MHz at things will solve the problem.The ultimate aim of this project is/was to replace the 8bit databus with a serial link, to create a remote mounting interface board, so this first step was to try and emulate one.The databus, along with various other bits, is controlled by a DSP/FPGA combo, so it's got plenty of processing power behind it to manage to read/write continually every 200uS. The original interface board is just a few 74 chips along with optocouplers/drivers, which I was planning to replace with some form of ARM processor with similar I/O.I suspect some form of FPGA/DSP is probably a better solution for this problem, however I know next to nothing about them

author: westfw
author_rank: Super Contributor
timestamp: October 04, 2014, 08:23:42 pm
content: QuoteThey probably have an 8MHz crystal, but the STM32 chips have a fancy clock circuit that can multiply that up to "full speed" for the particular chip on the board.As you say, that's still not certain to solve your problem.Some chips have special peripherals that can help with this sort of application. (Microchip's "Parallel Master Port", DMA capability on GPIO, or perhaps the configurable logic on Cypress PSoCs); They'll essentially latch external data based on external signals, instead of having to be polled continuously. If your databus has externally-insertable "wait states" (like a Z80) or asynchronous IO (like a 68000), you may be able to slow down the bus sufficiently to make a software solution work.

author: JDubU
author_rank: Frequent Contributor
timestamp: October 04, 2014, 08:40:07 pm
content: The STM32F100RB has a maximum internal core clock speed of 24MHz.http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1031/LN775/PF216844?sc=internet/mcu/product/216844.jspYou will need to software configure the internal clock PLL subsystem to multiply the external 8MHz crystal frequency up to the desired core frequency.Some STM32F4xx parts will run at a maximum core frequency of 180MHz.

author: mc
author_rank: Regular Contributor
timestamp: October 04, 2014, 08:43:32 pm
content: Oh, I had forgotten about the clock multiplier stuff, which would explain why I thought the discovery boards were faster.Just checked the user manual for the board I've been using and max clock speed mentioned is 24Mhz, although I need to dig into the settings to see what the default is.I do also have a STM32F4 board, which a quick scan of the usermanual mentions 168Mhz, although I'll have to go and find the full datasheet as it has a few options for configuring what OSC source is used and the user manual doesn't go into much detail other than having to swap/solder/desolder links.Thanks for the tips JDubU!

author: JDubU
author_rank: Frequent Contributor
timestamp: October 04, 2014, 09:01:12 pm
content: ST has a free tool for clock setup plus assignment of alternate functions to pins. It generates sample initialization code that implements your specific choices:http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/PF259242?icmp=stm32cubemx_pron_prcube_feb2014&sc=stm32cube-prAt the bottom of the page select the version of the software that matches the processor series that you are using.

author: Torrentula
author_rank: Regular Contributor
timestamp: October 05, 2014, 08:30:36 am
content: Quote from: mc on October 04, 2014, 08:03:34 pmYes this is where even a simple CPLD would excel as compared to a smallish/slow (in terms of ARMs) STM32, because you essentially tie all those 74 series chips together in a single package. Xilinx make some CPLDs in humane 44-pin QFPs.Is there a way to trigger a DMA transfer from an external pin? You might be able to capture a bunch of data and save it to memory and then check it later on to see if the address matches and if so send it out over whatever serial link you want to achieve. This of course only works if it's okay for the serial end of the communications to lag behind the parallel data bus transfers.

author: mc
author_rank: Regular Contributor
timestamp: October 05, 2014, 10:04:50 am
content: I've just managed to get the first Discovery board to run at 24MHz, however it's interrupt response time is still taking around 3uS to flip an LED. I'm guessing there''s some form of internal speed issue controlling that, so that option appears to be out.I may have a go later with one of the other discovery boards, to try their reaction time.I've just been doing a bit googling, and I see DangerousPrototypes/Seed do a couple Xilinix CPLD development boards, so I might order a couple. The biggest problem seems to be that I need to be able to read the address, compare the address, and then be reading the first data 3.5uS later. Then when required, flip to outputting data within similar time constraints.Having had a quick look over the current board, it looks like it uses a couple 74chips along with a set of line drivers. When it gets an address match (set via jumpers), it activates the board, then on every clock pulse, it must activate the line drivers in turn, either reading or writing data to the databus.I'm not too bothered about the serial link lagging slightly, as the input/outputs aren't that critical.I'm actually thinking lots of multicore cable might be an easier option, however I'm at the point where I want to see if this is doable!

author: mc
author_rank: Regular Contributor
timestamp: October 05, 2014, 09:23:43 pm
content: Just for info, I've done a little bit reverse engineering of the existing board, and it's quite simple in it's operation.At the start of the cycle, a 74HC85 comparator compares the 4bit address with settings jumpers, and if a match, it activates the board via a 74HC273 D-type flip flop. Then there is a 74HC161 presettable counter linked to a 74HC138 3to8-line decoder, which on each cycle of the Clock the 161 outputs is fed to the 138 which activates it's output pins in sequence, which is then fed in turn to another two 273 D-type flip flops which read the databus and control the outputs, after that four LVC541As line drivers are activated in turn to read the inputs and write the status to the databus, followed by a final LVC541A that places a signature check onto the databus.And all that takes place in under 20uS.Just goes to show that processing power is not always the answer.

author: dannyf
author_rank: Super Contributor
timestamp: October 05, 2014, 09:28:12 pm
content: QuoteWith a mcu, you can do it in way less than 20us.Just goes to show that how you do it matters a lot more than what you do it on.

author: dgtl
author_rank: Regular Contributor
timestamp: October 05, 2014, 09:39:09 pm
content: When performing the GPIO operations, use direct register access. The ST library usually adds unneeded code, that should be avoided on such time-critical use cases. Just write to the corresponding GPIO registers. Use GPIO BSRR registers to set/clear single bits to avoid unneccessary old value readback. Set the pin configuration (direction etc) outside ISR. When direction change is needed, use also direct register accesses instead of library calls.The use case of parallel bus slave device is not best suited for microcontroller applications; it would make much more sense to implement it in hardware (FPGA etc). You may get it working with a faster uC. Check where the GPIO registers are connected; cortex-m controllers have usually multiple internal busses and some are slower than others.You want that the GPIOs are connected directly to AHB bus near the CPU. It is still not as fast in number of clocks as some 8-bit controllers due to the latency caused by pipelined CPU, pipelined busses, flash accelerator cache misses etc. But when understanding the constraints and working with it, it can be faster overall (of course, you'll need much faster cpus, the 24MHz cortex-m3 bitbang latency can not compete with 20MHz AVR etc).

author: mc
author_rank: Regular Contributor
timestamp: October 05, 2014, 09:55:16 pm
content: I think the issue is the 32F100 has the peripheral bus locked to a set frequency, as even setting the PLL to get the core running at 24MHz, the interrupt response time remains constant, and that was using a BSRR to flip the LED.I can't find the relevant datasheet for that chip that gives all the details, as the official datasheet seems to be more of a basic information about key features, so there could be an option to change the peripheral bus prescalers I've not found. (I'm limping along on broken broadband just now so I'm avoiding downloading loads of PDFs that might not have the necessary info)Having looked at the other discovery boards I have in STM32CubeMX (it doesn't yet support the F1x series, so can't check the clock settings there), they have various prescaler options for the peripheral buses, with the F0 board being maxed out at 48MHz, and the F4 board at 84MHz for one of the buses and 48MHz for the other, so I'll throw some extra speed at the problem to see if it's doable.Failing that it's looking like a simpler uC combined with a CPLD may be a solution.

author: jadew
author_rank: Frequent Contributor
timestamp: October 05, 2014, 10:21:21 pm
content: Hey, several points here:1) If you don't set up the external crystal and the PLL settings, it will use the internal clock.2) An ARM chip is not the right choice, because it's not deterministic (some are, but most aren't) - the same instruction may execute in a different number of clock cycles depending on the state of the pipeline.3) The document you're looking for is called the Reference Manual (RM<somenumber>). The datasheet is more like a brochure for STM32 chips.4) Given that you're only trying to mask the first 4 bits, (GPIOB->IDR & 0x0F) should do it.5) Since your chip is rather slow for the task and you only want to forward data to the serial port (if I understand correctly), you may want to do it by pooling, instead of the interrupt way so you don't have to deal with the overhead of the interrupt.That being said, I'm still not clear on the timing constraints of the protocol you're working with, but a quick look over the LA screenshots would suggest that they're not that tight and that you should be able to do fine with a 24 MHz chip.I'm not sure about the STM32F0 family, but there's also a flash latency issue, so instructions may take a bit longer to get executed, because they need to be fetched first.To solve this, you can either put them in RAM or if the chip has that, enable instruction and data prefetch.If changing the chip is an option, I recommend a different type of MCU, like the Atmel's AVR or Xmega, or Microchip's PIC. They are deterministic and usually one instruction takes one cycle (at least for AVRs) so they may actually be a lot faster.

author: dannyf
author_rank: Super Contributor
timestamp: October 05, 2014, 10:32:42 pm
content: With a 20MIPS avr, I can get it done in just short of 1.3us; With optimization, that can be cut in half.There is room for additional speed gain, but marginal I think.

author: dannyf
author_rank: Super Contributor
timestamp: October 05, 2014, 10:33:10 pm
content: The issue is not the chip but how you use that chip.

author: westfw
author_rank: Super Contributor
timestamp: October 05, 2014, 11:14:21 pm
content: I looked at this sort of thing when I was contemplating using a modern microcontroller (like an AVR) as the memory system for a legacy microcontroller (like an 8051.) You might think that this would be relatively easy - the 8051 takes 12 cycles per instruction at about 12MHz, and works with 450ns memories. An AVR with 50ns instruction time should be able to do that, shouldn't it? It turned out to be a lot harder than I expected (and I gave up. Although it still might be possible if I let the "memory system" provide (and "stretch) the 8051 clock...)The issue seems to be mostly one of T(setup) vs T(hold). T(setup) is the amount of time that a signal (say, the address) is valid before the "latch" signal is asserted. T(hold) is how long the signal stays valid AFTER the latch signal is asserted. For a typical hardware bus interface, T(setup) is relatively long - the address is put out there, and some time is allowed for it to propagate through logic gates before the latch signal comes along. T(hold) tends to be much shorter; in hardware, you're just flipping a latch that already contains the data. This is rather BACKWARDS from the way you want things to go if you are implementing them in software! You would rather peek at the latch signal, and then when it toggles, read the address. Which requires that the address be valid some significant time AFTER the latch signal, rather than before the latch signal :-(So while a 20uS "memory simulator" should be pretty trivial to do on a 20MHz microcontroller, I think it's relatively likely that the actual signal edge timing will make it a lot more difficult, and perhaps impossible.You (Dannyf) can take that as a challenge - turn your STM32F030 (or your choice of other micro) into the memory system for an 8051 (offering half its flash space and half its RAM space as 8051 Program/data memory...) (although, part of my reason for giving up on this was the whole "why bother" aspect. An 8051 is of historical interest, but I don't really have THAT much interest in building one...)

author: mc
author_rank: Regular Contributor
timestamp: October 05, 2014, 11:56:45 pm
content: Jade, thanks for the info.I just checked and I do have the Reference Manual, which does have all the clock details I need. I'll put that oversight down to spending too much time on the problem yesterday!I've just gone over the example file I used to switch the clock speed, and it does set the peripheral bus prescalers /1, so they should be running 3 times faster, yet the LA never picked up any difference in interrupt response time. I've attached the code below to see if anybody can spot any obvious mistakes.As westfw has just highlighted, the issue is timing, and how long the data remains on the bus.From the point of the Start pulse falling, I have 1uS to read the address, and decide if I need to activate. There is then the problem that the output data only remains on the databus for about 0.2uS after the Clock falling edge, and it isn't guarateed to be on the databus at the Clock rising edge. The only way I can see arounf this is the time between the output bits/pulses is constant, so a simple time delay could be used to pre-empt the falling edge.The input pulses are slower, so I have about 1.5uS from clock rising to get the data on the bus ready for the clock falling and the data getting latched.I am thinking for reliability and guaranteeing timing, some form of logic gates forming a buffer to a uC would be a better idea, or even a FPGA with a softcore for handling the serial aspect.I had hoped to download the Xilinx software while I was out today so I could install it tonight and have a play, however their registration system seems to be broken and I still can't access the download

author: Zeta
author_rank: Contributor
timestamp: October 06, 2014, 12:41:56 am
content: just use a cheap CPLD. Lattice does cheap cplds in low pin count packages or if you insist on using an ARM (maybe because you want to do something else) then using a $1 PSOC4 to implement your logic in the UDBs would be as fast as the propagation delay (faster than your discrete 74 solution).

author: true
author_rank: Frequent Contributor
timestamp: October 06, 2014, 01:59:54 am
content: At ~80MHz, standard ISR response on a Cortex-M part to user code with a standard preamble is something like 300-600ns. For PIC32, it is ~600-800ns.Still, this isn't really the application for an MCU, though if you clock it high enough it could work. (I'm doing something similar for a project because the MCU fits into the price / complexity budget and it barely works in terms of speed/power consumption but it does work)Quote from: Zeta on October 06, 2014, 12:41:56 amIt might work if it isn't too complex, and they aren't $1 anymore =) about $2.50USD/qty1. But yes, this is a possible solution too.

author: Torrentula
author_rank: Regular Contributor
timestamp: October 06, 2014, 08:57:34 am
content: Quote from: mc on October 05, 2014, 11:56:45 pmNo need for a soft core there, if it's a simple serial protocol (i.e. RS232, SPI, I2C) it can be done in a relatively small FSM, again completely in logic.The Lattice MachXO2 CPLDs/non-volatile FPGAs come in a 32-pin QFN and are pretty cheap.

author: Jeroen3
author_rank: Super Contributor
timestamp: October 06, 2014, 09:48:51 am
content: If you tie clk or start to a timer pin capable of generating an interrupt. Such as capture, trigger or something else, you might be able to use the DMA to immediately copy the GPIO register data to ram.Or you get an LPC18/43 family chip with SGPIO, parallel <-> serial conversion perhipherals.Not sure if bitbanding is usefull for you, might be worth checking out.