Why can't I fully put Zynq-7000 into low power? - arm

Why does any of the following register writes cause my program to halt?
slcr.DDR_CLK_CTRL[DDR_2XCLKACT] = 0
slcr.DDR_CLK_CTRL[DDR_3XCLKACT] = 0
slcr.DDR_PLL_CTRL[PLL_BYPASS_FORCE] = 1
slcr.DDR_PLL_CTRL[PLL_PWRDWN] = 1
I'm new with embedded development and I'm trying to implement some bare bones C code to put the zynq 7000 into sleep mode per page 674 of the Technical Reference Manual
All of the sleep mode steps execute without issue except for the steps listed, all of which relate to DDR, and all of which halt execution. Leaving the DDR steps out the code functions but I'm not sure I'm reaching the lowest power state.
I'm using the on-board button of my Cora Z7-07S development board as an interrupt source. The handler for the interrupt on button-down executes the power down function and executes the wake function on button-up.
I followed this tutorial (video here) on my Cora Z7-07S to get the interrupt functioning. Does using the AXI GPIOs as an interrupt source create some dependence on DDR? Is there a way to setup the PL to avoid this and still allow a GPIO interrupt?

Related

Handling multiple interrupts with FreeRTOS on STM32

My MCU based control system must check 18 switch contact status fastly. I will use STM32F7 MCU and it has maximum 16 int. handler. So I have been decided to use IO expendar IC and divided groups. Now I have 12 IO external interrupt and 2 more interrupt comes from IO expander. In addition FreeRTOS will has ethernet, uart and canbus tasks for communications. Interrupts are very critical for system. There is milisecond difference between them and I have to detect all pins status correctly. I need and expert advice for this situation.
My questions are :
Is this a proper way ? Using 14 external interrupt onFreeRTOS that handles multiple communication task
Is there any better way for it ?
Using an IO expander seems like the wrong approach to your problem (additional complexity and cost). You don't have to assign a dedicated ISR to each pin. Just read the GPIOx_IDR register after any GPIO interrupt, then check the relevant bits STM32 Datasheet

Syncronizing 3 STM32L4 MCU's sine generators using one GPIO pin on each MCU

I have developed a custom STM32L475 board with one GPIO pin wired up for synchronization along some other circuitry for the synchronization, unfortunately we decided to route the generated sinus signal from module to module.
This is not optimal so I want to optimize so it is not the sinus signal which is routed from master module to slave modules, but to just transfer a digital trigger to restart the generation of a full sine wave.
To do this I need to be able to setup the MCU's to use the one GPIO pin on each MCU as both output and trigger for a timer.
To do this without an update of the HW I need to be able to combine:
1. Using the 3 pins (one from each MCU) as open drain outputs as an AND gate, this works.
2. I know the GPIO pin can be used as external trigger, triggering on a negative edge.
The question is, is it possible to trig a timer of an output pin using only one GPIO pin, to make the MCU which finalizes its sine generation first trigger itself and the other MCU's, and if so, how?
Please note, it must use the level of the output pin itself, eventhough it is an outputpin.
I am a HW developer, learning to do firmware for our HW, so I am kind of new to software development, so I am using HAL, please be nice
STM32L475 allows to configure a GPIO in different modes that must be (exclusively) selected through the corresponding GPIOx_MODER register:1
(Digital) Input mode
General purpose output mode
Alternate function mode
Analog mode
The alternate function applied in Alternate function mode must also be selected exclusively, through the corresponding GPIOx_AFRL or GPIOx_AFRH register, resp.2
The trigger for an interrupt or timer is an alternate function, and the output of a (analogue or digital) signal is a (different) alternate function, too.
Therefore, I think there is no solution to the given problem based on peripheral configuration.
1
Reference Manual, Rev 7:
See
Section 8.5.1 for GPIO mode selection
Figures 23/24 in Section 8.4 for explanation
2
ibid.:
See
Section 8.5.9 for GPIO alternate function selection
Section 8.4.2 for explanation

How to control CS signal in SPIDEV moudule on raspberry pi

I am trying to use SPIDEV module in Python 2.7 to interface Raspberry Pi 3 with ADS1256 ADC over the SPI bus available on the Raspberry Pi unit.
The project is to communicate with two of those ADCs and sample all the channels (8 channels each) at 250Hz sampling rate.
The functions in the SPIDEV module responsible for data transaction are xfer and xfer2. The problem with these functions is that they issue a CS active command (bring CS low), do the transaction and issue a CS release command (bring CS high). In order to communicate with ADS1256, a series of commands needs to be sent to the ADC while the CS is kept at logic low. This is possible by listing all the commands together and pass them to the xfer/xfer2 function like this:
$xfer2([10, 20, 30, 40])$
However, this way of sending commands do not give the ADC sufficient time to process each command or in other words, the timing between instructions violates the timing specifications of the ADC. If, on the other hand, one command is sent at a time, then the CS toggle causes the ADC to forget the previous command.
Two other alternatives suggested online that I tried, introduce too much delay that I cannot squeeze all channel reads within the time frame I have between each sampling instance. These alternatives are:
WiringPi module: This module has the wiringPiSPIDataRW function that is doing the data transaction only and CS can be controlled separately by IO functions in the module. The drawback is that time between each call to this function and as well as the time between bringing the CS low and calling this function is more than 200 microseconds which in aggregate will go over 4 milliseconds (my sampling period) when I sample all the channels.
Using a separate pin for CS when using SPIDEV: This option also introduced more than 100-microsecond delays between function calls.
These are the two suggestions that I have learned through digging Raspberry Pi community and Stack Overflow.
The xfer functions in SPIDEV also provide an argument called delay and according to the documentation it should control the delay between blocks but it only means that how long the CS should be kept low after a transaction is complete. For example: if I issue:
$xfer2([12, 23, 34, 46], 1800000, 30)$
It will keep CS low for 30 microseconds at the end only after sending 46 is over. It doesn't provide 30 microseconds between each byte i.e 12, 23, 34 and 46 which is an ideal thing that I need. However, if I do
xfer2([12])
xfer2([23])
xfer2([34])
xfer2([46])
of course, due to nature of Raspberry Pi, the time between each will be more than 100 microsecond which I cannot handle.
So something that will help me control the delay between commands is an ideal thing.
If not possible, something that will let me control CS in the xfer functions so they do not toggle it. Meaning that I can control the CS pin with IO functions. This will prevent a hardware modification on my board which is using the raspberry pi GPIO header CE pin as CS. Although it is still a slow solution but much faster than the functions in the wiringPi module.
In a worst case, I will have to modify my hardware and use a different GPIO pin to use as CS.
Thanks for reading

Can I disable Interrupts on a BBB for a short duration (0.5ms)?

I am trying to write a small driver program on a Beaglebone Black that needs to send a signal with timings like this:
I need to send 360 bits of information. I'm wondering if I can turn off all interrupts on the board for a duration of 500µs while I send the signal. I have no idea if I can just turn off all the interrupts like that. Searches have been unkind to me so far. Any ideas how I might achieve this? I do have some prototypes in assembly language for the signal, but I'm pretty sure its being broken by interrupts.
So for example, I'm hoping I could have something like this:
disable_irq();
/* asm code to send my bytes */
reenable_irq();
What would the bodies of disable_irq() and reenable_irq() look like?
The calls you would want to use are local_irq_disable() and local_irq_enable() to disable & enable IRQs locally on the current CPU. This also has the effect of disabling all preemption on the CPU.
Now lets talk about your general approach. If I understand you correctly, you'd like to bit bang your protocol over a GPIO with timing accurate to < 1/3 us.
This will be a challenge. Tests show that the Beaglebone black GPIO toggle frequency is going to max out at ~2.78MHz writing directly to the SoC IO registers in kernel mode (~0.18 us minimum pulse width).
So, although this might be achievable by the thinnest of margins by writing atomic code in kernel space, I propose another concept:
Implement your custom serial protocol on the SPI bus.
Why?
The SPI bus can be clocked up to 48MHz on the Beaglebone Black, its buffered and can be used with the DMA engine. Therefore, you don't have to worry about disabling interrupts and monopolizing your CPU for this one interface. With a timing resolution of ~0.021us (# 48MHz), you should be able to achieve your timing needs with an acceptable margin of error.
With the bus configured for Single Channel Continuous Transfer Transmit-Only Master mode and 30-bit word length (2 30-bit words for each bit of your protocol):
To write a '0' with your protocol, you'd write the 2 word sequence - 17 '1's followed by 43 '0's - on SPI (#48MHz).
To write a '1' with your protocol, you'd write the 2 word sequence - 43 '1's followed by 17 '0's - on SPI (#48MHz).
From your signal timmings it's easy to figure out that SPI or other serial peripheral can not reach your demand. In your timmings, encoding is based on the width of the pulse. So let's get to the point:
Q1 Could you turn off all interrupts for a duration of 500µs?
A: 0.5ms is quite a long time in embedded system. ISR is born to enable the concurrency of multi-task and improve the real-time capability. Your should keep in mind that ISR and context-switch(in some chip architecture) are all influenced by global interrupt.
But if your top priority is to perform the timmings, and the real-time window of other tasks are acceptable, of cause you can disable the global interrupt in the duration. Even longer. If not, don't do ATOM operation in such a long time.
Q2 How?
A: For a certain chip, there's asm instruction for open/close global interrupt undoubtedly. Find the instructions or the APIs provided by your OS, do the 3 steps below(pseudocode):
state_t tState = get_interrupt_status( );
disable_interrupt( );
... /*your operation here*/
resume_interrupt( tState );

scheduling tasks in linux

Can we schedule a program to execute every 5 ms or 10 ms etc?
I need to generate a pulse through the serial port for 1 khz and 15 khz.
But the program should only toggle the pins in the serial port , so the frequency has to be produced by a scheduler. is this possible in linux with a rt patch?
I believe a better solution is to put your "generate a pulse" function in a loop, for example:
for (;;) {
generate_pulse(); /* generate a pulse */
sleep(5ms); /* or 10ms */
}
is this possible in linux with a rt patch?
I suggest to go for RT patch, if timing is critical.
Xenomai is a RT patch which I used on 2.6 kernel some days back.
Here is an example which runs every 1 second.
http://www.xenomai.org/documentation/trunk/html/api/trivial-periodic_8c-example.html
There is the PPS project that is now part ( at least a portion of it for the 2.6 branch, but in the latest 3.x kernel branch it looks like there is a full integration ) of the mainline linux kernel.
There is also an explicit reference to using this PPS implementation with a serial port in the linked txt file
A PPS source can be connected to a serial port (usually to the Data
Carrier Detect pin) or to a parallel port (ACK-pin) or to a special
CPU's GPIOs (this is the common case in embedded systems) but in each
case when a new pulse arrives the system must apply to it a timestamp
and record it for userland.
Apparently good examples / tutorials / guides, are not even that hard to find , I'm sure that you'll find a lot of good resources while just using search engine.
The header for the APIs is usually under /usr/include/linux/pps.h .
I have finally found a way to get it done.
The best way to do it is to first create a timer with the required amount of time. and then to call the task( which is the pulse generating program) every time the timer overflows. The program for the timer can be run in the background. the timer can be created and set using the timer_create() and timer_settime() respectively. A different program can be called from one program using fork() and execl(). The program can be run in the background using the daemon().
By using all these things we can create our own scheduler.

Resources