__initdata 的奇怪影响

本文介绍了一次因__initdata修饰符引起的mfp寄存器配置问题及解决方案。通过调整修饰符,解决了蓝牙模块在不同工作模式下GPIO状态设置失效的问题。

__initdata 的奇怪影响

作者: 宋立新

Email:zjujoe@yahoo.com

 

恍然大悟后,当然也就不奇怪了。 不过当时 __initdata 修饰符确实给我们带来很大的困惑。

 

事情的经过是这样的。

 

通常我们设置mfp寄存器是在系统的启动阶段统一设置的, 所以 lc6830.c 中会有一个数组:

static mfp_cfg_t saar_mfp_cfg[] __initdata = {
RF_IF5_GPIO,
DF_INT_RnB_ND_INT_RnB,

};

 

系统初始化时,会调用:

pxa3xx_mfp_config(ARRAY_AND_SIZE(saar_mfp_cfg));

 

从而完成 mfp 寄存器的设置。

 

这里简单介绍一下 mfp 寄存器。

英文为: multi-function pin register

Marvell 的 AP 集成度很高, 为了以最小的 PIN 脚数量支持最多的功能, pxa935 上的绝大多数 pin 脚可以内部路由到 6 种不同的功能上。 路由到那个功能就通过 mfp 寄存器的第3位设置。

 

Mfp 还可以用于设置某个 PIN 脚在系统待机时的状态, 是输出高电平, 输出低电平,还是处于输入状态, 等等。

 

我们的蓝牙模块有几种工作模式:

在不使用蓝牙时,如果系统进入待机状态,则希望该模块处于最低功耗状态,此时,控制其power 的 GPIO 应该输出低, 以切换其电源。

 

而正在使用蓝牙功能时,如果系统进入待机状态,则希望该模块处于较低功耗状态,此时,控制其power 的 GPIO 应该输出高, 以保持正常的功能, 比如,能够唤醒 AP。

 

于是,模仿上面的数组,我们定义了如下数组:

 

322 static mfp_cfg_t __initdata wlan_bt_powerdown_high_mfp_cfg[] = {
323         GPIO174_BT_WIFI_POWER_GPIO_ON,
324 };
325 static mfp_cfg_t __initdata wlan_bt_powerdown_low_mfp_cfg[] = {
326         GPIO174_BT_WIFI_POWER_GPIO,
327 };

 

其中对 GPIO174 对应的 PIN 脚进行了相反的定义。 这样, 在打开蓝牙模块时,我们会调用:

pxa3xx_mfp_config(ARRAY_AND_SIZE(wlan_bt_powerdown_high_mfp_cfg));

而在关闭蓝牙模块时:

pxa3xx_mfp_config(ARRAY_AND_SIZE(wlan_bt_powerdown_low_mfp_cfg));

 

这样,确保该 PIN 脚处于合适的状态。

 

当时,使用工具 /root/bin/ureg_test 去读寄存器, 发现设置没有生效!

 

使用 trace32 跟踪代码, 发现该数组定义的数据结构各字段值不正确, 有时为0,有时为一些异常值!

 

苦思冥想, 终于发现定义数据结构时,直接模仿了 saar_mfp_cfg 的定义, 而 saar_mfp_cfg 只在开机时使用, 我们的数据却要在开机后使用!

 

将 __initdata 修饰符去掉后, 发现一切正常了!

 

说明: 所有 __init* 修饰的数据,函数都用于说明它们只在系统开机阶段使用,其占用的空间会在系统完成启动后释放。 此时, 它们不再有效。

 

package com.weishitech.jtwzjiaotongcx.fragment.lilv; import android.app.AlertDialog; import android.content.Context; import android.content.SharedPreferences; import android.text.Html; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.weishitech.jtwzjiaotongcx.R; import com.weishitech.jtwzjiaotongcx.adtakubase.activity.BaseBindActivity; import com.weishitech.jtwzjiaotongcx.bean.Question; import com.weishitech.jtwzjiaotongcx.databinding.ActivityDetailsBinding; import com.weishitech.jtwzjiaotongcx.fragment.Adapter.AnswerStatusAdapter; import com.weishitech.jtwzjiaotongcx.utils.OnMultiClickListener; import java.lang.reflect.Type; import java.util.List; public class AnswerDetailActivity extends BaseBindActivity<ActivityDetailsBinding> { private List<Question.DataBean> questionList; private RecyclerView recyclerView; private AnswerStatusAdapter adapter; @Override protected void init() { mBinding.ivBack.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { finish(); } }); recyclerView = mBinding.rv; recyclerView.setLayoutManager(new GridLayoutManager(this, 10)); // 每行10个题号 parseData(); setupAdapter(); displayScore(); //显示分数和处理 tv_type } private void parseData() { String json = getIntent().getStringExtra("questionList"); Log.d("AnswerDetail", "JSON length: " + (json != null ? json.length() : "null")); Log.d("AnswerDetail", "Raw JSON: " + json); if (json == null || json.isEmpty()) { Toast.makeText(this, "数据加载失败", Toast.LENGTH_SHORT).show(); finish(); return; } Type type = new TypeToken<List<Question.DataBean>>(){}.getType(); questionList = new Gson().fromJson(json, type); Log.d("AnswerDetail", "解析成功,题目数量: " + (questionList != null ? questionList.size() : "null")); } public class PreferenceKeys { public static final String LAST_EXAM_SCORE = "last_exam_score"; // 最近得分 public static final String LAST_EXAM_TIME = "last_exam_time"; // 考试时间 } /** * 显示分数,并根据是否及格决定是否显示 tv_type */ private void displayScore() { int correctCount = getIntent().getIntExtra("correctCount", 0); int totalCount = getIntent().getIntExtra("totalCount", 100); // 默认 100 题 int score = (int) (((double) correctCount / totalCount) * 100); mBinding.tvScore.setText(score + "分"); SharedPreferences sp = getSharedPreferences("exam_result", Context.MODE_PRIVATE); sp.edit() .putInt(PreferenceKeys.LAST_EXAM_SCORE, score) .putLong(PreferenceKeys.LAST_EXAM_TIME, System.currentTimeMillis()) .apply(); // 异步提交 Log.d("AnswerDetail", "已保存最近成绩: " + score + "分"); // 判断是否合格(科目一/四:90分合格) if (score >= 90) { mBinding.tvType.setVisibility(View.GONE); // 合格则不显示 } else { mBinding.tvType.setText("成绩不合格"); mBinding.tvType.setVisibility(View.VISIBLE); } } private void setupAdapter() { adapter = new AnswerStatusAdapter(questionList, position -> { showQuestionDetailDialog(position); }); recyclerView.setAdapter(adapter); } private void showQuestionDetailDialog(int position) { Question.DataBean q = questionList.get(position); AlertDialog.Builder builder = new AlertDialog.Builder(this); View dialogView = LayoutInflater.from(this).inflate(R.layout.dialog_question_detail, null); builder.setView(dialogView); TextView tvTitle = dialogView.findViewById(R.id.tv_question_title); TextView tvUserAnswer = dialogView.findViewById(R.id.tv_user_answer); TextView tvCorrectAnswer = dialogView.findViewById(R.id.tv_correct_answer); TextView tvAnalysis = dialogView.findViewById(R.id.tv_analysis); TextView btnClose = dialogView.findViewById(R.id.btn_close); ImageView btnImg = dialogView.findViewById(R.id.iv_img); tvTitle.setText((position + 1) + ". " + q.getTitle()); String userAns = q.getShowAnswer(); if (!userAns.isEmpty()) { tvUserAnswer.setText(userAns); } else { tvUserAnswer.setText("未作答"); } String titlePic = q.getTitlePic(); if (!titlePic.isEmpty()) { Glide.with(this) .load(q.getTitlePic()) .transform(new RoundedCorners(10)) // 圆角半径为30px .into(btnImg); }else { } tvCorrectAnswer.setText(q.getAnswer()); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { tvAnalysis.setText(Html.fromHtml(q.getAnalysis(), Html.FROM_HTML_MODE_LEGACY)); } else { tvAnalysis.setText(Html.fromHtml(q.getAnalysis())); } AlertDialog dialog = builder.create(); btnClose.setOnClickListener(v -> dialog.dismiss()); dialog.show(); } }package com.weishitech.jtwzjiaotongcx.fragment.lilv; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.RelativeLayout; import android.widget.TextView; import com.hfd.common.base.BaseFragment; import com.weishitech.jtwzjiaotongcx.R; import com.weishitech.jtwzjiaotongcx.utils.OnMultiClickListener; /** * 个人出租屋税率 */ public class LiLvFragment extends BaseFragment{ RelativeLayout relative01,relative02; TextView tv_results; @Override protected int setLayout() { return R.layout.fragment_lilv; } @Override protected void initView() { relative01 = fvbi(R.id.relative01); relative02 = fvbi(R.id.relative02); tv_results = fvbi(R.id.tv_results); } @Override protected void initClick() { relative01.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { handlerKSClck(11); } }); } @Override protected void initData() { SharedPreferences sp = getActivity().getSharedPreferences("exam_result", Context.MODE_PRIVATE); int lastScore = sp.getInt(AnswerDetailActivity.PreferenceKeys.LAST_EXAM_SCORE, -1); // -1 表示无记录 if (lastScore >= 0) { tv_results.setText("最近成绩:" + lastScore + "分"); } else { tv_results.setText("暂无考试记录"); } } private void handlerKSClck(int i) { Bundle bundle = new Bundle(); bundle.putInt("type",i); toClass(TestActivity.class,bundle); } }tv_results没显示分数,还是暂无考试记录
12-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值