fmodf() 是否会导致 stm32 出现硬故障?
Does fmodf() cause a hardfault in stm32?
我正在尝试用 2 个正弦波创建调制波形。
为此,我需要模数 (fmodf) 来了解具有特定频率 (lo_frequency) 的正弦波在当时 (t) 的振幅。但是当执行以下行时我遇到了硬故障:
j = fmodf(2 * PI * lo_frequency * t, 2 * PI);
你知道为什么这会给我一个 hardfault 吗?
编辑 1:
我用 my_fmodf 交换了 fmodf:
float my_fmodf(float x, float y){
if(y == 0){
return 0;
}
float n = x / y;
return x - n * y;
}
但是还是出现hardfault,调试的时候连这个函数都不跳(my_fmodf)。
这是发生此错误的整个函数:
int* create_wave(int* message){
/* Mixes the message signal at 10kHz and the carrier at 40kHz.
* When a bit of the message is 0 the amplitude is lowered to 10%.
* When a bit of the message is 1 the amplitude is 100%.
* The output of the STM32 can't be negative, thats why the wave swings between
* 0 and 256 (8bit precision for faster DAC)
*/
static int rf_frequency = 10000;
static int lo_frequency = 40000;
static int sample_rate = 100000;
int output[sample_rate];
int index, mix;
float j, t;
for(int i = 0; i <= sample_rate; i++){
t = i * 0.00000001f; // i * 10^-8
j = my_fmodf(2 * PI * lo_frequency * t, 2 * PI);
if (j < 0){
j += (float) 2 * PI;
}
index = floor((16.0f / (lo_frequency/rf_frequency * 0.0001f)) * t);
if (index < 16) {
if (!message[index]) {
mix = 115 + sin1(j) * 0.1f;
} else {
mix = sin1(j);
}
} else {
break;
}
output[i] = mix;
}
return output;
}
编辑 2:
我修复了警告:函数 returns address of local variable [-Wreturn-local-addr] 按照“chux - Reinstate Monica”建议的方式。
int* create_wave(int* message){
static uint16_t rf_frequency = 10000;
static uint32_t lo_frequency = 40000;
static uint32_t sample_rate = 100000;
int *output = malloc(sizeof *output * sample_rate);
uint8_t index, mix;
float j, n, t;
for(int i = 0; i < sample_rate; i++){
t = i * 0.00000001f; // i * 10^-8
j = fmodf(2 * PI * lo_frequency * t, 2 * PI);
if (j < 0){
j += 2 * PI;
}
index = floor((16.0f / (lo_frequency/rf_frequency * 0.0001f)) * t);
if (index < 16) {
if (!message[index]) {
mix = (uint8_t) floor(115 + sin1(j) * 0.1f);
} else {
mix = sin1(j);
}
} else {
break;
}
output[i] = mix;
}
return output;
}
但现在我在这一行遇到了硬错误:
output[i] = mix;
编辑 3:
因为前面的代码包含一个非常大的缓冲区数组,不适合 STM32F303K8 的 16KB SRAM,所以我需要更改它。
现在我使用“乒乓”缓冲区,其中我将 DMA 的回调用于“前半部分传输”和“完全传输”:
void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef * hdac){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
for(uint16_t i = 0; i < 128; i++){
new_value = sin_table[(i * 8) % 256];
if (message[message_index] == 0x0){
dac_buf[i] = new_value * 0.1f + 115;
} else {
dac_buf[i] = new_value;
}
}
}
void HAL_DAC_ConvCpltCallbackCh1 (DAC_HandleTypeDef * hdac){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
for(uint16_t i = 128; i < 256; i++){
new_value = sin_table[(i * 8) % 256];
if (message[message_index] == 0x0){
dac_buf[i] = new_value * 0.1f + 115;
} else {
dac_buf[i] = new_value;
}
}
message_index++;
if (message_index >= 16) {
message_index = 0;
// HAL_DAC_Stop_DMA (&hdac1, DAC_CHANNEL_1);
}
}
它按照我想要的方式工作:
但是创建的正弦频率太低了。
我的上限在 20kHz 左右,但我需要 40kHz。
我已经将时钟增加了 8 倍,因此时钟已达到最大值:
。
我仍然可以减少计数器周期(目前为 50),但是当我这样做时,中断回调似乎比下一个周期更长。
至少看起来是这样,因为当我这样做时输出变得非常失真。
我还尝试通过仅取第 8 个正弦值来降低精度,但是
我不能再这样做了,因为那样输出看起来就不再像正弦波了。
我有什么想法可以优化回调以减少它花费的时间吗?
还有其他想法吗?
Does fmodf() cause a hardfault in stm32?
这里是其他代码问题导致的硬故障
编译失败并出现大量警告
最佳代码提示:启用所有警告。
比 Whosebug 更快的反馈。
我希望在一个功能良好的编译器上有类似下面的东西。
return output;
warning: function returns address of local variable [-Wreturn-local-addr]
返回本地对象
不能return 本地数组。改为分配。
// int output[sample_rate];
int *output = malloc(sizeof *output * sample_rate);
return output;
调用代码需要free()
指针。
数组访问超出范围
static int sample_rate = 100000;
int output[sample_rate];
// for(int i = 0; i <= sample_rate; i++){
for(int i = 0; i < sample_rate; i++){
...
output[i] = mix;
}
堆栈溢出?
static int sample_rate = 100000; int output[sample_rate];
是一个很大的局部变量。也许分配或尝试更小的东西?
高级:精度损失
好fmodf()
不失精。要获得更精确的答案,请考虑中间结果的 double
数学。更好的方法涉及更多。
float my_fmodf(float x, float y){
if(y == 0){
return 0;
}
double n = 1.0 * x / y;
return (float) (x - n * y);
}
Can I not use any function within another ?
是的。代码还有其他问题。
1 个值每 10uS 仅产生 100kSPS whis 对于这个宏来说并不过分。在我的设计中,我可以毫无问题地生成 > 5MSPS 的信号。通常我有一个缓冲区和循环模式的 DMA。首先,我填充缓冲区并开始生成。当触发半传输 DMA 中断时,我用新数据填充缓冲区的前半部分。传输完成中断被触发,我填充下半部分,这个过程再次重复。
我正在尝试用 2 个正弦波创建调制波形。 为此,我需要模数 (fmodf) 来了解具有特定频率 (lo_frequency) 的正弦波在当时 (t) 的振幅。但是当执行以下行时我遇到了硬故障:
j = fmodf(2 * PI * lo_frequency * t, 2 * PI);
你知道为什么这会给我一个 hardfault 吗?
编辑 1:
我用 my_fmodf 交换了 fmodf:
float my_fmodf(float x, float y){
if(y == 0){
return 0;
}
float n = x / y;
return x - n * y;
}
但是还是出现hardfault,调试的时候连这个函数都不跳(my_fmodf)。
这是发生此错误的整个函数:
int* create_wave(int* message){
/* Mixes the message signal at 10kHz and the carrier at 40kHz.
* When a bit of the message is 0 the amplitude is lowered to 10%.
* When a bit of the message is 1 the amplitude is 100%.
* The output of the STM32 can't be negative, thats why the wave swings between
* 0 and 256 (8bit precision for faster DAC)
*/
static int rf_frequency = 10000;
static int lo_frequency = 40000;
static int sample_rate = 100000;
int output[sample_rate];
int index, mix;
float j, t;
for(int i = 0; i <= sample_rate; i++){
t = i * 0.00000001f; // i * 10^-8
j = my_fmodf(2 * PI * lo_frequency * t, 2 * PI);
if (j < 0){
j += (float) 2 * PI;
}
index = floor((16.0f / (lo_frequency/rf_frequency * 0.0001f)) * t);
if (index < 16) {
if (!message[index]) {
mix = 115 + sin1(j) * 0.1f;
} else {
mix = sin1(j);
}
} else {
break;
}
output[i] = mix;
}
return output;
}
编辑 2:
我修复了警告:函数 returns address of local variable [-Wreturn-local-addr] 按照“chux - Reinstate Monica”建议的方式。
int* create_wave(int* message){
static uint16_t rf_frequency = 10000;
static uint32_t lo_frequency = 40000;
static uint32_t sample_rate = 100000;
int *output = malloc(sizeof *output * sample_rate);
uint8_t index, mix;
float j, n, t;
for(int i = 0; i < sample_rate; i++){
t = i * 0.00000001f; // i * 10^-8
j = fmodf(2 * PI * lo_frequency * t, 2 * PI);
if (j < 0){
j += 2 * PI;
}
index = floor((16.0f / (lo_frequency/rf_frequency * 0.0001f)) * t);
if (index < 16) {
if (!message[index]) {
mix = (uint8_t) floor(115 + sin1(j) * 0.1f);
} else {
mix = sin1(j);
}
} else {
break;
}
output[i] = mix;
}
return output;
}
但现在我在这一行遇到了硬错误:
output[i] = mix;
编辑 3:
因为前面的代码包含一个非常大的缓冲区数组,不适合 STM32F303K8 的 16KB SRAM,所以我需要更改它。
现在我使用“乒乓”缓冲区,其中我将 DMA 的回调用于“前半部分传输”和“完全传输”:
void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef * hdac){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
for(uint16_t i = 0; i < 128; i++){
new_value = sin_table[(i * 8) % 256];
if (message[message_index] == 0x0){
dac_buf[i] = new_value * 0.1f + 115;
} else {
dac_buf[i] = new_value;
}
}
}
void HAL_DAC_ConvCpltCallbackCh1 (DAC_HandleTypeDef * hdac){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
for(uint16_t i = 128; i < 256; i++){
new_value = sin_table[(i * 8) % 256];
if (message[message_index] == 0x0){
dac_buf[i] = new_value * 0.1f + 115;
} else {
dac_buf[i] = new_value;
}
}
message_index++;
if (message_index >= 16) {
message_index = 0;
// HAL_DAC_Stop_DMA (&hdac1, DAC_CHANNEL_1);
}
}
它按照我想要的方式工作:
但是创建的正弦频率太低了。
我的上限在 20kHz 左右,但我需要 40kHz。
我已经将时钟增加了 8 倍,因此时钟已达到最大值:
我还尝试通过仅取第 8 个正弦值来降低精度,但是 我不能再这样做了,因为那样输出看起来就不再像正弦波了。
我有什么想法可以优化回调以减少它花费的时间吗? 还有其他想法吗?
Does fmodf() cause a hardfault in stm32?
这里是其他代码问题导致的硬故障
编译失败并出现大量警告
最佳代码提示:启用所有警告。
比 Whosebug 更快的反馈。
我希望在一个功能良好的编译器上有类似下面的东西。
return output;
warning: function returns address of local variable [-Wreturn-local-addr]
返回本地对象
不能return 本地数组。改为分配。
// int output[sample_rate];
int *output = malloc(sizeof *output * sample_rate);
return output;
调用代码需要free()
指针。
数组访问超出范围
static int sample_rate = 100000;
int output[sample_rate];
// for(int i = 0; i <= sample_rate; i++){
for(int i = 0; i < sample_rate; i++){
...
output[i] = mix;
}
堆栈溢出?
static int sample_rate = 100000; int output[sample_rate];
是一个很大的局部变量。也许分配或尝试更小的东西?
高级:精度损失
好fmodf()
不失精。要获得更精确的答案,请考虑中间结果的 double
数学。更好的方法涉及更多。
float my_fmodf(float x, float y){
if(y == 0){
return 0;
}
double n = 1.0 * x / y;
return (float) (x - n * y);
}
Can I not use any function within another ?
是的。代码还有其他问题。
1 个值每 10uS 仅产生 100kSPS whis 对于这个宏来说并不过分。在我的设计中,我可以毫无问题地生成 > 5MSPS 的信号。通常我有一个缓冲区和循环模式的 DMA。首先,我填充缓冲区并开始生成。当触发半传输 DMA 中断时,我用新数据填充缓冲区的前半部分。传输完成中断被触发,我填充下半部分,这个过程再次重复。