time delay in simulink to be used with c code generation
14 Comments
Hi @Sadia,
When you introduce a for loop that does not have any side effects (i.e., it does not modify any variables or produce output), the code generator recognizes it as redundant and optimizes it out. This is why your attempts to create a delay using a for loop have not been successful. Similarly, introducing a dummy variable may not work as expected because the code generator can still rearrange the order of operations based on its optimization algorithms. So, to achieve the desired timing without the code generator optimizing away the delay, we can utilize the Simulink Delay block or a combination of Simulink blocks to create a timed sequence. Below is a simplified example of how to implement this:
% Simulink Model Setup model = 'STM32_Segment_Display'; open_system(model);
% Create a new model
new_system(model);
add_block('built-in/Constant', [model '/Clock_High']);
set_param([model '/Clock_High'], 'Value', '1');
add_block('built-in/Constant', [model '/Clock_Low']);
set_param([model '/Clock_Low'], 'Value', '0');
add_block('built-in/Delay', [model '/Delay']);
set_param([model '/Delay'], 'DelayLength', '2e-6'); % 2 microseconds
add_block('built-in/Outport', [model '/Out']);
set_param([model '/Out'], 'Port', '1');
% Connect blocks add_line(model, 'Clock_High/1', 'Delay/1'); add_line(model, 'Delay/1', 'Out/1'); add_line(model, 'Clock_Low/1', 'Out/1');
% Save and build the model save_system(model); slbuild(model);
So, in this code, I created a new Simulink model named STM32_Segment_Display which consists of the following components:
Clock High and Low Constants: These blocks represent the high and low states of the clock pin. The Constant blocks are set to output 1 (high) and 0 (low) respectively.
Delay Block: The Delay block is configured to introduce a delay of 2 microseconds. This is crucial for ensuring that the clock pin remains high for the required duration before transitioning to low.
Outport Block: The Outport block is used to send the output signal to the STM32F411RE board.
Connections: The blocks are connected in a sequence where the Clock_High output goes into the Delay block, and the output of the Delay block is then sent to the Out port. The Clock_Low can be similarly connected to ensure the clock pin goes low after the delay.
Addressing your concern regarding to prevent the code generator from optimizing away the delay, you have to make sure that the Delay block is properly configured and connected in the model. The use of a Delay block is preferred over a for loop, as it provides a clear and functional way to introduce timing without being optimized out.
After implementing these changes, validate the timing using an oscilloscope or logic analyzer to ensure that the delays are functioning as expected. Please let me know if this approach helped resolve your problem.
Hi @Sadia,
Use a Mux block or a Switch block. I will prefer Mux block because it will combine multiple signals into a single vector, which can then be sent to the Outport. For more information on this block, please refer to
https://www.mathworks.com/help/simulink/slref/mux.html
Here’s how you can modify your model:
Add a Mux Block:Use the command add_block('built-in/Mux', [model '/Mux']); to create a Mux block in your model.
How to Connect Signals to the Mux:
Connect the output of the Delay block to one input of the Mux.
Connect the output of the Clock_Low block to another input of the Mux.
Connect the Mux to the Outport:
Finally, connect the output of the Mux to the Outport.
Here’s a simplified code snippet to illustrate this:
% Add Mux block
add_block('built-in/Mux', [model '/Mux']);
set_param([model '/Mux'], 'Inputs', '2'); % Set number of inputs to 2
% Connect blocks add_line(model, 'Delay/1', 'Mux/1'); % Connect Delay to Mux add_line(model, 'Clock_Low/1', 'Mux/2'); % Connect Clock_Low to Mux add_line(model, 'Mux/1', 'Out/1'); % Connect Mux to Outport
This approach will maintain the integrity of your model while allowing you to send multiple signals to a single Outport. Please try this modification and let me know if it resolves your issue.
Hi @Sadia,
Your existing loop structure is a good start, but there are a few adjustments you can make to improve timing control. For example, instead of using arbitrary delays (Delay_us), consider implementing a more efficient method to manage timing. Using hardware timers or interrupts which can help you achieve more precise control over signal transitions without blocking your main program execution. If your microcontroller supports it, set up a timer interrupt that triggers at regular intervals corresponding to your desired clock frequency. In the interrupt service routine (ISR), toggle the CLK line and manage data transmission without explicitly using delays in your main loop. Here’s an example code snippet for simplified version of how you might structure this using timer interrupts.
void Timer_ISR() {
static unsigned char bit_index = 0; if (bit_index < 8) {
Clk = 0; // Set clock low
dio = (oneByte & 0x01) ? 1 : 0; // Set data line based on LSB
Delay_us(3); // Short delay for data setup
Clk = 1; // Set clock high
Delay_us(3); // Delay for data hold time oneByte >>= 1; // Shift right to prepare for next bit
bit_index++;
} else {
bit_index = 0; // Reset after sending all bits
// Optionally handle stop condition here
}
}Hope this helps.
Hi @Sadia,
After going through documentation listed at https://www.mathworks.com/help/ecoder/STM32f4xx-based-boards.html?s_tid=CRUX_lftnav
and addition to my above comments, I will now recommend utilizing hardware timers and interrupts effectively to manage your signal transitions without excessive software delays. In my opinion, it will allow you to achieve more precise timing and a more sustainable implementation.Here’s a basic outline of how you can structure your code to use timers for controlling your clock signal while sending bits using “c” language. For more information on “ #include "stm32f4xx_hal.h", please refer to
Code to use timers for controlling your clock signal while sending bits
#include "stm32f4xx_hal.h"
TIM_HandleTypeDef htim2; // Assuming TIM2 is used for timing volatile uint8_t oneByte;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
static uint8_t bitIndex = 0;
if (htim->Instance == TIM2) {
if (bitIndex < 8) {
Clk = 0; // Set CLK low
dio = (oneByte & 0x01) ? 1 : 0; // Set DIO based on the current bit
oneByte >>= 1; // Shift right to process the next bit
// Prepare for next cycle
bitIndex++;
} else {
Clk = 1; // Set CLK high after sending all bits
bitIndex = 0; // Reset for next byte
}
}
}void setupTimer() {
// Configure TIM2 to generate an interrupt every specific microsecond (for example, every 3us)
__HAL_RCC_TIM2_CLK_ENABLE();
htim2.Instance = TIM2;
htim2.Init.Prescaler = 84 - 1; // Assuming 84 MHz clock, adjust as needed
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 300 - 1; // Adjust this value for timing (3us)
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim2);
HAL_TIM_Base_Start_IT(&htim2); // Start timer with interrupts enabled
}int main(void) {
HAL_Init();
setupTimer();
while (1) {
// Main loop can handle other tasks or prepare data to send
oneByte = ...; // Load your data here
HAL_Delay(100); // Example delay between bytes if needed
}
}Explanation of the Code Structure
Timer Initialization: The setupTimer function initializes TIM2 to generate an interrupt every specified period (e.g., every 3 microseconds). The prescaler is set according to the system clock frequency.
Interrupt Handling: In HAL_TIM_PeriodElapsedCallback, handle what happens each time the timer overflows. Here I manage the clock and data output according to the current bit being sent. The Clk signal is toggled appropriately based on the current state.
Main Loop: In the main loop, you can prepare data (`oneByte`) that needs to be sent. This allows for flexibility in managing when to send new data without blocking execution.
I also utilized interrupts method which offloads timing control from your main application logic, allowing it to run more smoothly without needing busy-wait delays. Please make sure that your timer configurations align with your hardware specifications and desired timing accuracy. Adjust the prescaler and period values as needed based on your clock speed.
Hopefully, by implementing this approach, you should find that it greatly enhances the sustainability and reliability of your communication protocol without overwhelming your main program flow with delays.
Hi @Sadia,
Please see my response to your comments below.
To address your first query regarding, My problem is whenever I try to include the a C function (using coder.ceval etc) in a Matlab function block, initially it gives errors such as cannot find header files such as "stm32f4xx_hal_conf.h" etc
The error regarding missing header files such as "stm32f4xx_hal_conf.h" indicates that the MATLAB environment cannot locate the necessary STM32 HAL library files. This is often due to incorrect paths or missing configurations in the MATLAB setup.
Now, addressing your second query, operand mismatch for ds, Error: no such instruction: `dmb 0xF etc.
The assembler errors, such as "operand mismatch for ds" and "no such instruction: `dmb 0xF," suggest that the assembly code generated by the C code is not compatible with the target architecture or that the compiler settings are not correctly configured for the STM32 platform.
My suggestion would be at this point would be integrating the C code into MATLAB, test the C code in a standalone environment (e.g., an STM32 IDE) to ensure that it compiles and runs correctly. This can help isolate whether the issue is with the C code itself or the integration with MATLAB.
After reading your comments about “I am not very well versed with C and assembly language so I don't really understand this. I have tried googling it but no luck specifically in Matlab.”
I may suggest how exactly are you compiling code since I have no clue what is going on your side of “ interface a STM32F411RE board with a 4 digital seven segment display via simulink”
So, please provide some detailed instructions and let’s follow a step by step process in order to accomplish your goal. Otherwise, exchanging these ideas back and forth and not knowing how are you interfacing your board with simulink will not help reach your target goal. Hope, you understand.
Answers (1)
0 votes
- Open the Model Configuration Parameters dialog box from the Settings. Then, navigate to the Simulation Target tab.
- In the advanced parameters section, uncheck the option labeled Block reduction. This will prevent the code generator from simplifying blocks that are crucial for timing accuracy.
- Go to the Code Generation tab and then select Optimization.
- Consider setting the Optimization levels option to Minimum. This setting reduces the extent to which the code is optimized, preserving your intended logic.
- Alternatively, it can be set to Balanced with readability or Maximum if those settings better suit the needs.
- If either Balanced with readability or Maximum is chosen, enable Specify custom optimization and uncheck the option Eliminate superfluous local variables (expression folding). This prevents the code generator from folding expressions that might interfere with timing logic.
3 Comments
- Create a MATLAB Function Block:
- In your Simulink model, add a MATLAB Function block.
- Double-click the block to open the editor and define the delay function. Use coder.ceval to call a custom C function:
- Create a file named delay.c with the following content:
- Create a delay.h file to declare the function:
- In the Model Settings under Code Generation > Custom Code, specify the delay.c and delay.h files in the appropriate sections for source and header files.
- In the Source files field, enter the name of your custom source file, e.g., delay.c. If the file is not in the current working directory, provide the full path or relative path from the model file location.
- In the Header files field, enter the name of your custom header file, e.g., delay.h. Similar to source files, provide the full path if necessary.
- If you need to include any specific initialization code or additional functions, you can add them in the Include directives field. For example, you might add #include "delay.h" if it is not already included in your code.
Categories
Find more on MATLAB in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!