当前位置:  编程技术>移动开发
本页文章导读:
    ▪基于GridView LoadMoreAsync 设计的横向双向飞瀑流 组件 源码分享        基于GridView LoadMoreAsync 设计的横向双向瀑布流 组件 源码分享原理: 实现了ISupportIncrementalLoading 接口 完成了增量加载, 针对于本地对象无法释放的情况 增加了 相关的Func 同时 通过VisualTree 拿.........
    ▪ MyGui札记(4)渲染过程        MyGui笔记(4)渲染过程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 void BaseManager::drawOneFrame() {     // First we clear the screen and depth buffer     // 首先清除屏幕和深度缓冲     glClear(GL_COLOR_BUFFER_B.........
    ▪ Tiny210 U-BOOT(6)-DDR内存配置       Tiny210 U-BOOT(六)----DDR内存配置上次讲完了Nand Flash的低级初始化,然后Nand Flash的操作主要是在board_init_f_nand(),中,涉及到将代码从Nand Flash中copy到DDR中,这个放到后面实际移植的过程中再结合.........

[1]基于GridView LoadMoreAsync 设计的横向双向飞瀑流 组件 源码分享
    来源: 互联网  发布时间: 2014-02-18
基于GridView LoadMoreAsync 设计的横向双向瀑布流 组件 源码分享

原理:

实现了ISupportIncrementalLoading 接口

完成了增量加载,

针对于本地对象无法释放的情况 增加了 相关的Func

同时 通过VisualTree 拿到了GridView中 HorizontalBar 来对滚动条的位置进行捕捉 与计算

通过计算后 来执行 虚化操作

 

如需 转载请声明博客作者

 

以下是源码:

 

IncrementalLoadingCollection 对象:

 public class IncrementalLoadingCollection<T> : ObservableCollection<T>, ISupportIncrementalLoading
    {
        // 是否正在异步加载中
        private bool _isBusy = false;

        // 提供数据的 Func
        // 第一个参数:增量加载的起始索引;第二个参数:需要获取的数据量;第三个参数:获取到的数据集合
        private Func<int, int, List<T>> _funcGetData;
        // 最大可显示的数据量
        private uint _totalCount = 0;

        private Func<T, T> _actDisposeData;

        public int PageIndex = 0;

        public uint perCount = 0;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="totalCount">最大可显示的数据量</param>
        /// <param name="getDataFunc">提供数据的 Func</param>
        public IncrementalLoadingCollection(uint totalCount, Func<int, int, List<T>> getDataFunc, Func<T, T> actDisposeData)
        {
            _funcGetData = getDataFunc;
            _totalCount = totalCount;
            _actDisposeData = actDisposeData;
        }

        /// <summary>
        /// 是否还有更多的数据
        /// </summary>
        public bool HasMoreItems
        {
            get { return this.Count < _totalCount; }
        }

        /// <summary>
        /// 异步加载数据(增量加载)
        /// </summary>
        /// <param name="count">需要加载的数据量</param>
        /// <returns></returns>
        public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
        {
            perCount = count;
            if (_isBusy)
            {
                return AsyncInfo.Run((token) => Task.Run<LoadMoreItemsResult>(() =>
                {
                    return new LoadMoreItemsResult { Count = (uint)this.Count };

                }, token));
            }
            _isBusy = true;

            var dispatcher = Window.Current.Dispatcher;

            return AsyncInfo.Run(
                (token) =>
                    Task.Run<LoadMoreItemsResult>(
                       async () =>
                       {
                           try
                           {
                               //// 模拟长时任务
                               await Task.Delay(100);

                               // 增量加载的起始索引
                               var startIndex = this.Count;

                               await dispatcher.RunAsync(
                                    CoreDispatcherPriority.Normal,
                                    () =>
                                    {
                                        PageIndex++;
                                        // 通过 Func 获取增量数据
                                        var items = _funcGetData(startIndex, (int)count);
                                        if (items != null)
                                            foreach (var item in items)
                                            {
                                                this.Add(item);
                                            }
                                    });

                               // Count - 实际已加载的数据量
                               return new LoadMoreItemsResult { Count = (uint)this.Count };
                           }
                           finally
                           {
                               _isBusy = false;
                           }
                       },
                       token));
        }

        public void DisposeItemByStartAndEnd(long start, long end)
        {
            for (long i = start; i < end; i++)
            {
                _actDisposeData(this.Items[(int)i]);
            }
        }

        public void RemoveItemByRange(long start, long end)
        {
            for (long i = start; i < end; i++)
            {
                if (this.Items.Count > i)
                {
                    this.RemoveItem((int)i);
                }
            }
        }

        public void Reset()
        {
            this.OnCollectionChanged(new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Reset));
        }
    }


IncrementalLoadingGridView:

 

  public class IncrementalLoadingGridView : GridView
    {
        #region Member Variables
        private ScrollBar _HorizontalScrollBar;
        private Dictionary<int, int> _pageOffsetDict = new Dictionary<int, int>();
        private Dictionary<int, bool> _pageVirtualizingDict = new Dictionary<int, bool>();
        private dynamic _filelist;
        #endregion

        #region Constants
        const string HORIZONTALSCROLLBAR_PARTNAME = "HorizontalScrollBar";
        #endregion

        public IncrementalLoadingGridView()
        {
            this.Loaded += ((sender, e) =>
            {
                this.OnApplyTemplate();
            });
            this.Unloaded += ((sender, e) =>
            {
                _HorizontalScrollBar = Pollute.FindVisualChildByName<ScrollBar>(this, HORIZONTALSCROLLBAR_PARTNAME);
                if (null != _HorizontalScrollBar)
                    _HorizontalScrollBar.ValueChanged -= ValueChanged;
            });

        }

        protected override async void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            await this.WaitForLayoutUpdateAsync();
            _HorizontalScrollBar = Pollute.FindVisualChildByName<ScrollBar>(this, HORIZONTALSCROLLBAR_PARTNAME);
            if (null != _HorizontalScrollBar)
            {
                _HorizontalScrollBar.ValueChanged += ValueChanged;
            }
        }

        protected override async void OnItemsChanged(object e)
        {
            if (null != this.ItemsSource)
            {
                InitPositionByValue();
            }

            base.OnItemsChanged(e);
            if (null == this.ItemsSource)
            {
                await this.WaitForLoadedAsync();
                InitPositionByValue();
            }
        }

        private void InitPositionByValue()
        {
            _filelist = this.ItemsSource;
            CompositionTarget.Rendering += ((obj, args) =>
            {
                var newValue = Convert.ToInt32(_HorizontalScrollBar.Value);
                int currentPageIndex = _filelist.PageIndex - 2;
                if (!_pageOffsetDict.ContainsKey(currentPageIndex))
                {
                    _pageOffsetDict[currentPageIndex] = newValue;
                    _pageVirtualizingDict[currentPageIndex] = false;
                }
            });
        }

        private int preIndex = 0;
        private int maxPageIndex = 0;
        private int minOffset;
        private async void ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
        {
            if (null == this.ItemsSource) return;
            var newValue = Convert.ToInt32(e.NewValue);
            var oldValue = Convert.ToInt32(e.OldValue);
            if (newValue == oldValue) return;
            Debug.WriteLine("坐标:" + newValue);
            int currentPageIndex;
            if (null == _filelist) _filelist = this.ItemsSource;
            if (e.NewValue < 1.0)
            {
                await Task.Run(async () =>
                {
                    string text = "滑到头了 开始释放 释放前个数:" + _filelist.Count.ToString();
                    Debug.WriteLine(text);
                    for (int i = 3; i < maxPageIndex; i++)
                    {
                        _pageVirtualizingDict[i] = true;
                        var start = (i - 1) * _filelist.perCount;
                        var end = i * _filelist.perCount - 1;
                        await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
                        {
                            if (_filelist.Count > end)
                            {
                                _filelist.DisposeItemByStartAndEnd(start, end);
                                _filelist.RemoveItemByRange(start, end);
                            }
                            await Task.Delay(500);
                            _filelist.Reset();
                        });
                    }
                    _filelist.PageIndex = 2;
                    text = "滑到头了 释放完毕 释放后个数:" + _filelist.Count;

                    Debug.WriteLine(text);
                });
            }
            else
                await Task.Run(() =>
                {
                    if (newValue > oldValue)
                    {
                        //lock (_pageOffsetDict)
                        //{
                        var horiOffset = newValue - oldValue;
                        if (minOffset > horiOffset) minOffset = horiOffset;
                        currentPageIndex = _filelist.PageIndex - 2;
                        //_pageOffsetDict[currentPageIndex] = newValue;
                        maxPageIndex = Convert.ToInt32(_filelist.Count) / Convert.ToInt32(_filelist.perCount);

                        //}
                        if (preIndex != currentPageIndex && _pageOffsetDict.ContainsValue(newValue))
                        {
                            Debug.WriteLine("坐标:" + newValue + " 上一页:" + preIndex + " 当前页:" + currentPageIndex);
                            if (_pageVirtualizingDict.ContainsKey(preIndex))
                            {
                                _pageVirtualizingDict[preIndex] = false;
                                Debug.WriteLine("@@@@@@@@@@@@@@@@@@@@@@@@@需要向后虚化:" + preIndex + "@@@@@@@@@@@@@@@@@@@@@@" + _pageVirtualizingDict[preIndex]);
                                if (!_pageVirtualizingDict[preIndex] && preIndex > 3)
                                {
                                    int i = preIndex;
                                    while (i > 3)
                                    {
                                        //if (!_pageVirtualizingDict.ContainsKey(i))
                                        //{
                                        //    _pageVirtualizingDict[i] = false;
                                        //    _pageOffsetDict[i] = oldValue -= minOffset;
                                        //}
                                        if (_pageVirtualizingDict.ContainsKey(i) && !_pageVirtualizingDict[i])
                                        {
                                            var start = (i - 3) * _filelist.perCount;
                                            var end = (i - 2) * _filelist.perCount - 1;
                                            _filelist.DisposeItemByStartAndEnd(start, end);
                                            _pageVirtualizingDict[i] = true;
                                            Debug.WriteLine("虚化完毕:" + i);
                                        }
                                        i--;
                                    }
                                }
                            }
                            preIndex = currentPageIndex;
                        }
                        _pageVirtualizingDict[currentPageIndex] = false;
                    }
                    else if (newValue < oldValue)
                    {
                        if (_pageOffsetDict.ContainsValue(newValue))
                        {
                            currentPageIndex = _pageOffsetDict.GetKey(newValue).FirstOrDefault();
                            Debug.WriteLine("当前页:" + currentPageIndex + " 坐标:" + newValue);
                            var offset = 3;
                            if (preIndex - offset > currentPageIndex && currentPageIndex > 0)
                            {
                                _pageVirtualizingDict[preIndex] = false;
                                if (!_pageVirtualizingDict[preIndex])
                                {
                                    Debug.WriteLine("@@@@@@@@@@@@@@@@@@@@@@@@@虚化 After页:" + preIndex + " 是否虚化" + _pageVirtualizingDict[preIndex]);
                                    int i = preIndex - offset;
                                    while (i <= maxPageIndex)
                                    {
                                        //if (!_pageVirtualizingDict.ContainsKey(i))
                                        //{
                                        //    _pageVirtualizingDict[i] = false;
                                        //    _pageOffsetDict[i] = oldValue += minOffset;
                                        //}
                                        if (_pageVirtualizingDict.ContainsKey(i) && !_pageVirtualizingDict[i])
                                        {
                                            Debug.WriteLine("开始释放第:" + i + "页");
                                            int count = _filelist.Count;
                                            Debug.WriteLine("虚化前个数:" + count);
                                            var start = (i - 1) * _filelist.perCount;
                                            var end = i * _filelist.perCount - 1;
                                            if (end < _filelist.Count)
                                            {
                                                _filelist.DisposeItemByStartAndEnd(start, end);
                                            }
                                            string writeLine = "虚化after完毕 虚化位Start:" + start + " End:" + end + " Page:" + i + " 虚化后个数:" + count;
                                            Debug.WriteLine(writeLine);
                                            _pageVirtualizingDict[i] = true;
                                        }
                                        i++;
                                    }
                                }
                                _pageVirtualizingDict[currentPageIndex] = false;
                                //_pageVirtualizingDict[currentPageIndex - 1] = false;
                                //_pageVirtualizingDict[currentPageIndex - 2] = false;
                                //_pageVirtualizingDict[currentPageIndex - 3] = false;
                                preIndex = currentPageIndex;
                            }
                            _pageVirtualizingDict[currentPageIndex] = false;
                        }
                    }

                });
            if (e.NewValue == _HorizontalScrollBar.Maximum)
            {
                this.IsHitTestVisible = false;
                await Task.Delay(500);
                this.IsHitTestVisible = true;
            }
        }
    }


使用方式:

    <toolkit:IncrementalLoadingGridView x:Name="gvMain"
                      Visibility="{Binding IsLeafLevel, Converter={StaticResource BooleanToVisibilityConverter}}"
                      Padding="140,40,0,0"
                      SelectionMode="None"
                      ItemsSource="{Binding ImageItemsSource, Mode=TwoWay}"
                      IncrementalLoadingThreshold="0.5" DataFetchSize="0.5"
                      IsItemClickEnabled="True"
                      PointerMoved="gvMain_PointerMoved"
                      ItemClick="gvMain_ItemClick"
                     ItemTemplateSelector="{StaticResource imageDataTemplateSelector}">
                <GridView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapGrid VirtualizingStackPanel.VirtualizationMode="Recycling"></WrapGrid>
                    </ItemsPanelTemplate>
                </GridView.ItemsPanel>
            </toolkit:IncrementalLoadingGridView>


IncrementalLoadingThreshold="0.5" DataFetchSize="0.5" 这2个阀值设定的比较低 这样虚化起来效率会高一些

 

需要binding 的列表对象

Dispose方法 需要binding对象继承IDispose 释放本地流

_filelist = new IncrementalLoadingCollection<FileItem>((uint)_currentfiles.Count, (startIndex, Count) =>
            {
                SetLoadingState(true);
                if (_currentfiles == null || _currentfiles.Count <= startIndex) return null;
                List<FileItem> list = new List<FileItem>();
                foreach (var file in _currentfiles.Skip(startIndex).Take(Count))
                {
                    FileItem item = new FileItem();
                    item.File = file;
                    item.Name = file.DisplayName;
                    if (folder.Name.EndsWith("zhx")) item.Name = "zhx" + item.Name;
                    list.Add(item);
                }
                SetLoadingState(false);
                return list;
            }, (o) =>
            {
                o.Dispose();
                return o;
            });


 

 

当增量滚动时 我会针对 触发增量加载事件同时 记录 需要虚化的offset 在回滚的同时 进行释放操作,以保证内存在较低的负载。

在超宽屏幕上的使用效果, 载入了大量本地图片

 

1楼Menger86昨天 13:32神作

    
[2] MyGui札记(4)渲染过程
    来源: 互联网  发布时间: 2014-02-18
MyGui笔记(4)渲染过程

前篇:《MyGui笔记(3)控件对齐方式和所在层》
本篇:记录下渲染的过程。
环境:MyGui3.2.0(OpenGL平台)

        MyGui的渲染过程比较复杂,这里仅记录一下一些要点,如有错误的地方,还请指出。在第一篇有提到在BaseManager::run函数里面进行每一帧的绘制,调用的是drawOneFrame()方法,这个方法代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void BaseManager::drawOneFrame()
{
    // First we clear the screen and depth buffer
    // 首先清除屏幕和深度缓冲
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Then we reset the modelview matrix
    // 然后重置模型视图矩阵
    glLoadIdentity();

    if (mPlatform)
        mPlatform->getRenderManagerPtr()->drawOneFrame();

    SwapBuffers(hDC);
}

调用的是OpenGLRenderManager的drawOneFrame()方法,代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void OpenGLRenderManager::drawOneFrame()
{
    Gui* gui = Gui::getInstancePtr();
    if (gui == nullptr)
        return;

    static Timer timer;
    static unsigned long last_time = timer.getMilliseconds();
    unsigned long now_time = timer.getMilliseconds();
    unsigned long time = now_time - last_time;

    onFrameEvent((float)((double)(time) / (double)1000));

    last_time = now_time;

    begin();
    onRenderToTarget(this, mUpdate);
    end();

    mUpdate = false;
}

在这里进行每一帧事件的触发,和每一帧的渲染,渲染调用其onRenderToTarget方法,代码如下: 

1
2
3
4
5
6
void RenderManager::onRenderToTarget(IRenderTarget* _target, bool _update)
{
    LayerManager* layers = LayerManager::getInstancePtr();
    if (layers != nullptr)
        layers->renderToTarget(_target, _update);
}

可以看到在这里调用的是LayerManager层管理器来进行绘制,具体代码如下: 

1
2
3
4
5
6
7
void LayerManager::renderToTarget(IRenderTarget* _target, bool _update)
{
    for (VectorLayer::iterator iter = mLayerNodes.begin(); iter != mLayerNodes.end(); ++iter)
    {
        (*iter)->renderToTarget(_target, _update);
    }
}

对mLayerNodes里的所有层依次进行调用渲染,故定义在MyGUI_Layers.xml文件最上面的层,将会最先开始渲染,顺序如Wallpaper→Back→Overlapped→……。具体的渲染方法是根据不同的层类型来进行的,代码分别如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void SharedLayer::renderToTarget(IRenderTarget* _target, bool _update)
{
    if (mChildItem != nullptr)
        mChildItem->renderToTarget(_target, _update);

    mOutOfDate = false;
}

void OverlappedLayer::renderToTarget(IRenderTarget* _target, bool _update)
{
    for (VectorILayerNode::iterator iter = mChildItems.begin(); iter != mChildItems.end(); ++iter)
        (*iter)->renderToTarget(_target, _update);

    mOutOfDate = false;
}

在这里可以看到SharedLayer只进行了一次渲染,而OverlappedLayer对附加的根控件节点依次进行渲染,最终调用的都是LayerNode::renderToTarget方法,代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void LayerNode::renderToTarget(IRenderTarget* _target, bool _update)
{
    mDepth = _target->getInfo().maximumDepth;

    // 检查压缩空隙
    bool need_compression = false;
    for (VectorRenderItem::iterator iter = mFirstRenderItems.begin(); iter != mFirstRenderItems.end(); ++iter)
    {
        if ((*iter)->getCompression())
        {
            need_compression = true;
            break;
        }
    }

    if (need_compression)
        updateCompression();

    // 首先渲染
    for (VectorRenderItem::iterator iter = mFirstRenderItems.begin(); iter != mFirstRenderItems.end(); ++iter)
        (*iter)->renderToTarget(_target, _update);

    for (VectorRenderItem::iterator iter = mSecondRenderItems.begin(); iter != mSecondRenderItems.end(); ++iter)
        (*iter)->renderToTarget(_target, _update);

    // 现在绘制子节点
    for (VectorILayerNode::iterator iter = mChildItems.begin(); iter != mChildItems.end(); ++iter)
        (*iter)->renderToTarget(_target, _update);

    mOutOfDate = false;
}

渲染调用的方法为RenderItem::renderToTarget,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
void RenderItem::renderToTarget(IRenderTarget* _target, bool _update)
{
    if (mTexture == nullptr)
        return;

    mRenderTarget = _target;

    mCurrentUpdate = _update;

    if (mOutOfDate || _update)
    {
        mCountVertex = 0;
        Vertex* buffer = mVertexBuffer->lock();
        if (buffer != nullptr)
        {
            for (VectorDrawItem::iterator iter = mDrawItems.begin(); iter != mDrawItems.end(); ++iter)
            {
                // 在调用之前记住缓冲区的位置
                mCurrentVertex = buffer;
                mLastVertexCount = 0;

                (*iter).first->doRender();

                // 数量惊人的顶点绘制
                MYGUI_DEBUG_ASSERT(mLastVertexCount <= (*iter).second, "It is too much vertexes");
                buffer += mLastVertexCount;
                mCountVertex += mLastVertexCount;
            }

            mVertexBuffer->unlock();
        }

        mOutOfDate = false;
    }

    // 虽然0不是批次显示,但它仍然不会产生状态和操作
    if (0 != mCountVertex)
    {
#if MYGUI_DEBUG_MODE == 1
        if (!RenderManager::getInstance().checkTexture(mTexture))
        {
            mTexture = nullptr;
            MYGUI_EXCEPT("texture pointer is not valid, texture name '" << mTextureName << "'");
            return;
        }
#endif
        //直接渲染
        if (mManualRender)
        {
            for (VectorDrawItem::iterator iter = mDrawItems.begin(); iter != mDrawItems.end(); ++iter)
                (*iter).first->doManualRender(mVertexBuffer, mTexture, mCountVertex);
        }
        else
        {
            _target->doRender(mVertexBuffer, mTexture, mCountVertex);
        }
    }
}

注释是俄语的,谷歌翻译成汉语,可能会有错误,还请指出。最后的渲染即调用OpenGLRenderManager::doRender方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void OpenGLRenderManager::doRender(IVertexBuffer* _buffer, ITexture* _texture, size_t _count)
{
    OpenGLVertexBuffer* buffer = static_cast<OpenGLVertexBuffer*>(_buffer);
    unsigned int buffer_id = buffer->getBufferID();
    MYGUI_PLATFORM_ASSERT(buffer_id, "Vertex buffer is not created");

    unsigned int texture_id = 0;
    if (_texture)
    {
        OpenGLTexture* texture = static_cast<OpenGLTexture*>(_texture);
        texture_id = texture->getTextureID();
        //MYGUI_PLATFORM_ASSERT(texture_id, "Texture is not created");
    }

    glBindTexture(GL_TEXTURE_2D, texture_id);

    glBindBuffer(GL_ARRAY_BUFFER, buffer_id);

    // enable vertex arrays
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    // before draw, specify vertex and index arrays with their offsets
    size_t offset = 0;
    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offset);
    offset += (sizeof(float) * 3);
    glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offset);
    offset += (4);
    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offset);

    glDrawArrays(GL_TRIANGLES, 0, _count);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
}
更多资料:
1.纯手绘的MyGUI类图、渲染流程图 http://blog.csdn.net/liigo/article/details/7078533
2.LayerManager  http://blog.csdn.net/geometry_/article/details/7324348
3.mygui跟踪 http://www.cppblog.com/flipcode/archive/2011/06/24/149388.aspx

 


    
[3] Tiny210 U-BOOT(6)-DDR内存配置
    来源: 互联网  发布时间: 2014-02-18
Tiny210 U-BOOT(六)----DDR内存配置
上次讲完了Nand Flash的低级初始化,然后Nand Flash的操作主要是在board_init_f_nand(),中,涉及到将代码从Nand Flash中copy到DDR中,这个放到后面实际移植的过程中再结合源码流程来分析,正常来说,DDR应该是放在Nand Flash前面开始讲,因为DDR相对于Nand Flash来说,更加复杂一些,所以,将DDR拖后来讲,OK,接着开始讲DDR。

Tiny210 U-BOOT(六)----DDR内存配置
1.S5PV210内存芯片简介
最左边的四片就是内存芯片,是DDR2-800,这表示数据传输频率为800MHz,外部时钟频率200MHz,内部时钟频率为100MHz;因为内部一次传输的数据就可供外部接口传输4次,虽然以DDR方式传输,但数据传输频率的基准——外部时钟频率仍要是内部时钟的两倍才行。

我的板子上显示芯片型号为K4T1G084QF,打开三星的DDR2芯片命名规则文档(这个文档上网去搜索):
1~3. 比较简单,表示是DDR2内存;
4~5. Density,表示容量为1Gbit = 1Gbit/8 = 128MByte

6~7. Bit Organization,表示数据有多少bit,这里是08,则表示数据为8bit,四片拼起来,数据线就是32位。


8. # of Internal Banks,表示多少Bank,这里是4,表示为8个Banks
9. Interface, VDD, VDDQ,这里解释一下这两个电压的意思
VDD:北桥芯片供电电压或者存储芯片的输入缓冲和核心逻辑的供电电压。
VDDQ:存储芯片的输出缓冲供电电压。
Q : SSTL_18, 1.8V, 1.8V,根据芯片手册得出这两个电压为1.8V
10. Generation
F : F-die,这是什么意思???
芯片上型号K4T1G084QF,再往上看,会看到有四个BCF7的字母,接着看代表什么意思
12. Package
B : FBGA (Lead-Free & Halogen-Free, Flip Chip),表示这FBGA封装,FBGA是Fine-Pitch Ball Grid Array(意译为“细间距球栅阵列”)的缩写
13. Temp, Power
C : Commercial Temp.(0°C ~ 85°C), Normal Power,表示工作的温度范围和供电
14~15. Speed (Wafer/Chip Biz/BGD: 00)
F7 : DDR2-800 (400MHz@CL=6, tRCD=6, tRP=6),表示为DDR2-800的内存
分析完成,开发板上共有4片这样的内存芯片,总容量就是128M*4=512M

2.分析硬件原理图
2.1 从芯片角度
地址线:
A0-A13 14根
BA0,BA1,BA2
3根BA线表示这个芯片被分成了2^3=8个Bank,每个Bank则为128M/8=16M

这里出现一个问题,为什么128M里面还要划分出8个Bank?
前面在Nand Flash的时候,我曾经分析过,由于DDR是不自备充电电路的,所以,每隔一段时间,内存控制器就会刷新一次电路,也就是要充一次电,如果只有一个Bank,那么结果就是在某一时刻,要么都充电,要么都不充电。

像上面这样分成了8个Bank,当我对000充电的时候,我还可以在010或是剩下的别的Bank中读取数据,这样就减小了等待的时间,不用说当电路刷新时,不能读取数据了。
数据线:DQ0-DQ7*4 = 8bit * 4chips = 32bit
控制线:nCS,nRAS,nCAS
nCS:片选信号,当这个芯片被片选后,这个芯片就使能了,如果这芯片地址线上有地址,那么基本上数据线上就要出数据了。
地址线是A0-A13,是14根线,2^14=16K (128M = 2^27),所以地址线上地址要发两次,一次发行地址,一次发列地址,这就是行列地址复用--nRAS,nCAS这两根线的作用。
14 + 14 = 28根 + BA0/BA1/BA2 = 2^31=2G,最大支持2G的内存
128M = 2^27,27 - 3 = 24,行地址14根,所以,发过来的列地址是24-14=10
所以说,这个操作顺序是,先片选,CS拉低,然后,当RAS拉低时,表示传过的是行地址,是A0-A13,14位;当CAS拉低时,表示传过来的是列地址,是A0-A9,那列地址多的几位怎么办呢?很简单,用来扩展内存,谁说一片内存芯片就只能128M了?

2.2 从处理器角度
地址线 Xm1ADDR0-Xm1ADDR13
Xm1BA0, Xm1BA1, Xm1CSn1/BA2
数据线 Xm1DATA0-Xm1DATA31
控制线 Xm1CSn0, Xm1RASn, Xm1CASn  
对于地址线前面的Xm1,可以参看核心板的原理图中内存的总图,整个内存分为三块,Memory Port0/Memory Port1/Memory Port2,Memory Port1/Memory Port2分别对应于芯片手册P29页中Memory Map中的DRAM0/DRAM1,可以分别接两组不同的DDR内存

而Memory Port0接的是SRAM,他的地址线是0~15,没有行地址,列地址,没有复用,所以他的容量就是2^16=64K

2.3DDR芯片手册
前面在查看芯片的型号命名规则时最后两位,我们的板子上是F7
14~15. Speed (Wafer/Chip Biz/BGD: 00)
F7 : DDR2-800 (400MHz@CL=6, tRCD=6, tRP=6),表示为DDR2-800的内存

打开K4T1G084QF.pdf的DDR芯片手册,P4的Key Features,由此我们得知,我们要看的是DDR2-800 6-6-6

这里又多出和几个我们不认识的东西----CL,tRCD,tRP,看字面意思,大概来猜应该是一些时间,从芯片手册的命名规则上特意用一个字母代号来标识这三个东西,这肯定是非常重要的影响内存性能的某些时间参数。这里,有必要把DDR的工作原理重新梳理一下,这样,才能理解这些参数的意义。


 




    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
网络技术 iis7站长之家
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3